{"info":{"name":"PeskyBird","description":"The part of the PeskyBird push API that scripts and servers use with an app token. Bodies and responses are JSON unless stated; clients must ignore unknown response fields.","version":"0.1.0-alpha.4","schema":"https://schema.getpostman.com/json/collection/v2.1.0/collection.json"},"auth":{"type":"bearer","bearer":[{"key":"token","value":"{{appToken}}","type":"string"}]},"variable":[{"key":"baseUrl","value":"https://peskybird.app/api/push","type":"string","description":"This server’s push API."},{"key":"appToken","value":"","type":"string","description":"An app token (pba_…) from the dashboard's App tokens page."},{"key":"topic","value":"alerts","type":"string","description":"The topic to send to."},{"key":"messageId","value":"","type":"string","description":"Set by each send, for \"Check a send\"."}],"item":[{"name":"Send text to a topic","request":{"method":"POST","header":[{"key":"Content-Type","value":"text/plain"},{"key":"Title","value":"Disk almost full","description":"Sets `title`."},{"key":"Priority","value":"high","description":"Sets `priority`: `low`, `normal`, `high`, `critical`."},{"key":"Format","value":"","description":"Sets `format`: `text` or `markdown`.","disabled":true},{"key":"Image","value":"","description":"Sets `image`, an https URL.","disabled":true},{"key":"Url","value":"https://grafana.example.com/d/disk","description":"Sets `url`, opened from the message."},{"key":"Replaces","value":"disk-nas-01","description":"Sets `replaces`.","disabled":true},{"key":"Idempotency-Key","value":"{{$guid}}","disabled":true}],"url":{"raw":"{{baseUrl}}/topics/{{topic}}","host":["{{baseUrl}}"],"path":["topics","{{topic}}"],"query":[{"key":"dryRun","value":"true","description":"`true` checks the send without making it: the body, the token's topics and the topic are validated and `queued` counts the devices it would reach, but nothing is stored, sent, created or counted toward limits.","disabled":true}]},"body":{"mode":"raw","raw":"/var is at 91% on nas-01","options":{"raw":{"language":"text"}}},"description":"Publish to the topic named in the path\n\nThe one-line form. The topic is in the path; the body is plain text or JSON.\n\nAlso accepts a `text/plain` or `application/x-www-form-urlencoded` body (what `curl -d` sends), taken verbatim as `body`, neither parsed nor URL-decoded. On such a request the `Title`, `Priority`, `Format`, `Image` and `Url` headers set those fields and are validated like them; on a JSON request they are ignored. Anything else needs JSON."},"event":[{"listen":"test","script":{"type":"text/javascript","exec":["const result = pm.response.json();","if (pm.response.code === 201 && result.messageId && !result.dryRun) pm.collectionVariables.set('messageId', result.messageId);"]}}],"response":[]},{"name":"Send a JSON message","request":{"method":"POST","header":[{"key":"Content-Type","value":"application/json"},{"key":"Idempotency-Key","value":"{{$guid}}","disabled":true}],"url":{"raw":"{{baseUrl}}/messages","host":["{{baseUrl}}"],"path":["messages"],"query":[{"key":"dryRun","value":"true","description":"`true` checks the send without making it: the body, the token's topics and the topic are validated and `queued` counts the devices it would reach, but nothing is stored, sent, created or counted toward limits.","disabled":true}]},"body":{"mode":"raw","raw":"{\n  \"topic\": \"{{topic}}\",\n  \"title\": \"New order\",\n  \"body\": \"Order #1042 · 2 items · $86.00\",\n  \"priority\": \"high\",\n  \"url\": \"https://shop.example.com/orders/1042\",\n  \"actions\": [\n    {\n      \"id\": \"open\",\n      \"title\": \"Open order\",\n      \"url\": \"https://shop.example.com/orders/1042\"\n    },\n    {\n      \"id\": \"ship\",\n      \"title\": \"Mark shipped\",\n      \"url\": \"https://shop.example.com/orders/1042/ship\"\n    }\n  ],\n  \"data\": {\n    \"orderId\": \"1042\"\n  },\n  \"expiresInMs\": 86400000\n}","options":{"raw":{"language":"json"}}},"description":"Publish a message to a topic\n\nThe JSON form, with the topic in the body. Every option is available.\n\n`payload_too_large` is returned before parsing when the body exceeds `maxBodyBytes`; `invalid_request` when a field exceeds its own limit; `forbidden` when the topic is outside the token's `topicScope`."},"event":[{"listen":"test","script":{"type":"text/javascript","exec":["const result = pm.response.json();","if (pm.response.code === 201 && result.messageId && !result.dryRun) pm.collectionVariables.set('messageId', result.messageId);"]}}],"response":[]},{"name":"Check a send","request":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/sends/{{messageId}}","host":["{{baseUrl}}"],"path":["sends","{{messageId}}"]},"description":"A sent message and how many devices it reached\n\nWhat happened to a message you sent: how many devices it was handed to, and how many the push service accepted.\n\nFor a message on a topic the token may send to. With deferred fan-out, poll until `complete`."},"response":[]},{"name":"Check your token","request":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/token","host":["{{baseUrl}}"],"path":["token"]},"description":"The app token making the request\n\nChecks a token without sending anything: its name, the topics it may send to and its account.\n\nChecks a token without sending: its name, the topics it may send to and its account."},"response":[]},{"name":"List your topics","request":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/topics","host":["{{baseUrl}}"],"path":["topics"]},"description":"The topics this token may send to, with how many devices receive each\n\nThe topics a token may send to, and how many devices receive each, so you know someone will get the message.\n\nEvery topic for a token without a scope; the scope's names for one with a scope, including names with no topic yet."},"response":[]},{"name":"Check your limits","request":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/limits","host":["{{baseUrl}}"],"path":["limits"]},"description":"The limits on this account's sends and how much is used\n\nHow much of the daily message limit is used and when it resets, plus the other limits, without sending."},"response":[]},{"name":"List your devices","request":{"method":"GET","header":[],"url":{"raw":"{{baseUrl}}/devices","host":["{{baseUrl}}"],"path":["devices"]},"description":"The paired devices, for sending to some of them\n\nThe paired devices and the topics each receives. Put their ids in a send's `devices` to reach only some of them.\n\nRevoked devices are left out. A send's `devices` takes these ids; a device still has to receive the topic."},"response":[]},{"name":"Server info","request":{"method":"GET","auth":{"type":"noauth"},"header":[],"url":{"raw":"{{baseUrl}}/.well-known/peskybird","host":["{{baseUrl}}"],"path":[".well-known","peskybird"]},"description":"Server identity, protocol range and exposed groups\n\nDescribes the server: its name, the protocol versions it speaks and what it exposes. No token needed; useful as a health check."},"response":[]}]}