Guides

Send messages

Every message is one request: a POST to /v1/send. Start with a line of text, then add a title, a link, an alert level, a thread or a safe retry as you need them.

You need a send key in RIPPLE_KEY. An API token with full access can send too.

Send a line of text

Plain text becomes the message:

Terminal
curl https://api.ripplepush.com/v1/send \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -d "Backup finished"

Ripple trims spaces and blank lines from the ends. The message takes its source's default alert and link.

To send a file, use --data-binary, which keeps its line breaks. curl's plain -d @file removes them.

Terminal
curl https://api.ripplepush.com/v1/send \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  --data-binary @report.txt

For anything beyond text, send JSON:

Terminal
curl https://api.ripplepush.com/v1/send \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Deploy failed",
    "body": "The build needs attention.",
    "alert": "important",
    "sound": "knock",
    "link": "https://ci.example.com/builds/42",
    "linkTitle": "Open build"
  }'
Important

Include Content-Type: application/json. Without it, curl sends the JSON as form data, and Ripple answers 400 invalid_payload rather than posting the raw JSON as your message.

Every field is optional, but a message needs some text in a title or a body.

FieldWhat it does
titleA short headline, up to 120 characters. Without one, the body's first line is the headline
bodyThe message, up to 64,000 characters
linkAn https:// address to open from the message, up to 2,048 characters
linkTitleThe link's label, up to 64 characters
alertquiet, standard or important
soundWhich sound plays, if one would
threadGroups related updates; see threads
sourceWhere an API token sends; leave it out with a send key
  • A title over 120 characters is shortened, never mid-emoji, and the response adds a warning.
  • A link's length is counted again after any URL encoding.
  • The sounds are hop, arcade, clink, drop, echo, glow, knock, lift, sparkle, swoop, tick and wave. Without sound, a message plays its source's sound, or else the account's.
  • With an API token, source takes a source ID from Sources. Without it, the message goes to Inbox.

Limits count characters as JavaScript does, so most emoji count as two.

Choose how loudly it alerts

An alert level says how much a message matters. The person receiving it decides how loud that is.

LevelWhat it does
quietSaves the message without alerting a device
standardAlerts the usual way, but stays silent during quiet hours
importantAlerts through quiet hours too, and asks for more prominent presentation where the device supports it. It can't force an interruption.

Without alert, a message takes its source's default, or standard if the source has none. At any level, the message is saved and counts as unread.

sound picks the sound only when one would play anyway. Quiet messages, quiet hours and turned-off sounds all stay silent.

Group updates into a thread

When one job sends a series of updates, such as a deploy moving through its steps, put them in a thread so they read as one conversation. Send thread and body, without title:

JSON
{ "thread": "Production deploy", "body": "Tests passed" }

The next update with the same thread name, from the same source, joins it. Names match regardless of capitals and extra spaces, and can be up to 120 characters. A new update doesn't bring an archived thread out of the archive.

Retry without sending twice

When a send times out, you can't tell whether Ripple got it. An idempotency key makes the retry safe. It's any unique string you choose for the message, sent as a header:

Terminal
curl https://api.ripplepush.com/v1/send \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Idempotency-Key: deploy-42" \
  -d "Deploy 42 finished"

For 24 hours, the same key with the same message to the same source returns the first response instead of making a second message. The same key with a different message gets 409 idempotency_mismatch. The CLI does this for you: ripple send gives every message a key and retries with it.

Tip

Retry with exactly what you sent the first time, leaving out any field you left out, even if the source's defaults have changed since. Use a new key for each new message.

Read the response

A send that works returns 202 Accepted, which means Ripple saved the message:

202 Accepted
{
  "status": "accepted",
  "messageId": "msg_426dd54d815b4bfaaf0940b606cd0806",
  "source": { "kind": "system", "id": "src_9fddbdcb785848c6b10b068facd32d87", "label": "Inbox" },
  "receivedAt": "2026-10-02T12:00:01.000Z"
}

source says where the message went. Its kind is system for Inbox and custom for a source you made. A threaded send also returns thread, and a shortened title adds warnings.

When a send fails

Every error has the same shape: a code for your script and a message for people.

400 Bad request
{ "code": "missing_content", "message": "Provide at least one of title or body." }

Match on code; the wording of message can change.

StatusWhat it means
400The message needs fixing: no title or body, an unknown field, or a source that isn't the key's.
401The key is missing or no longer works. See Keys and tokens.
403The source is disabled or in Trash, or the API token is read-only. Enable or restore the source, or use a full-access token.
409The idempotency key was used for a different message.
413The request is too large.
415The body isn't JSON, plain text or curl's default form data.
429Too many sends: an account can send 60 a minute and a source 20, and a source over its limit pauses for 15 minutes. Wait the Retry-After seconds.
500Something went wrong on Ripple's side.
503Ripple is busy for a moment. Wait the Retry-After seconds.

After a 500 or 503, retry with the same idempotency key and message: the first attempt may have been saved.

Text with a NUL character or a broken Unicode sequence is turned away before anything is saved. Every response has an x-request-id header; include it if you ever ask about a request.

The API reference lists every field, limit and error code.