API reference › Sending

Send a JSON message

POSThttps://peskybird.app/api/push/messages
Auth App tokenBody application/json

The JSON form, with the topic in the body. Every option is available.

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.

Query parameters

  • dryRuntrue | false

    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.

Request headers

  • Idempotency-Keystring

    Any string up to 255 characters, unique per send (a UUID, say). Sending again with the same key within 24 hours returns the first send's result instead of sending twice. The same key with a different request, or while the first send is still running, is refused with 409 conflict.

    at most 255 characters

Request body JSON

  • topicstringRequired

    Created on first use when the server auto-creates topics.

    at most 32 characters
  • titlestring

    Shown above the body. At most 256 characters.

    at most 256 characters
  • bodystringRequired

    The message text, required. At most 2048 characters; Markdown when format is markdown.

    at most 2048 characters
  • prioritylow | normal | high | critical

    low, normal (default), high or critical. Each transport maps it to its own levels.

    default "normal"
  • urlURL

    Opened on tap.

    at most 2048 characters
Show 7 more optional fields
  • actionsobject[]

    Up to 4 buttons shown with the notification.

    at most 4 items
    Fields of each item (3)
    • idstringRequired

      Stable action identifier chosen by the publisher.

      at most 32 characters
    • titlestringRequired

      Button label.

      at most 64 characters
    • urlURL

      Opened when the action is tapped.

      at most 2048 characters
  • dataobject (string values)

    String key-value pairs delivered with the message for the receiving app; at most 16 keys and 1024 bytes serialized. Keys starting with _ are reserved.

    at most 16 keys
  • formattext | markdown

    How body is rendered. Default text. A markdown body is limited to the same 2048 characters.

  • imageURL

    HTTPS URL of an image the phone downloads itself, at most 2048 chars. The server stores the URL and never fetches it.

    at most 2048 characters
  • expiresInMsinteger

    Relative TTL in milliseconds, at most 30 days; the server stores expiresAt.

    more than 0at most 2592000000
  • devicesstring[]

    Restrict fan-out to these device ids; they must still be subscribed to the topic.

    at most 200 items
  • replacesstring

    A key you choose, 1 to 32 letters, digits, ., _, : or -. A later message on the same topic with the same key takes the earlier one's place on the phone instead of adding a notification (disk-nas-01: 91%, then 95%, then resolved).

    at most 32 characters

Response 201

Stored and fanned out (or queued).

  • messageIdstringRequired

    Id of the stored message. On a dry run, the id it would have had; nothing is stored.

  • queuedintegerRequired

    Devices handed to the queue.

  • sentintegerRequired

    Deliveries reported sent before the response; 0 when fan-out is deferred.

  • failedintegerRequired

    Deliveries that failed on the first attempt; 0 when fan-out is deferred.

  • dryRunboolean

    Present on a dry run: the send was checked and queued counts the devices it would reach, but nothing was stored, sent or counted.

Headers: RateLimit-Policy, RateLimit, Idempotent-Replayed. Usage headers

Errors

400invalid_request: A field is missing, too long or of the wrong type, or a header has a value it does not accept.
401unauthorized: The Authorization header is missing, or the token is not valid or has been revoked.
403forbidden: The token may not send to this topic, or the account does not allow what was asked. details.reason says which: topic_limit, images_not_enabled or account_suspended.
409conflict: The Idempotency-Key was already used with a different request, or the first send with it has not finished.
413payload_too_large: The request body is over 16 KB.
429rate_limited: The account reached its daily limit, or the token sent too fast.

Every error uses the same envelope. Error format and codes