API reference

Messages

List, read, search, organize and snooze messages and threads.

List messages

GET/v1/messages

Lists messages from every source, or from one, most recently updated first. With in=snoozed, the message coming back soonest is first. A thread shows up once, as its latest message. For the next page, pass nextCursor as cursor; new messages can shift results between pages.

AuthAPI token

Query parameters

  • instring · default all

    allarchivesnoozed

    Which messages to list. all, the default, lists messages that are neither archived nor snoozed; archive lists archived messages; and snoozed lists messages waiting to come back.

  • sourceIdstring · starts with src_

    A source ID, for only that source's messages. Use Inbox's ID, from GET /v1/sources, for Inbox. Leave it out for every source.

  • unreadboolean

    true lists only unread messages and false only read ones. Leave it out for both. A thread is read or unread as a whole, as its readAt shows, and counts once, the same way source unread counts do.

  • cursorstring

    The nextCursor from the previous page. Keep the other filters the same.

  • limitinteger · 1–100 · default 50

    The most items to return in one page.

Responses

  • 200

    One page of messages

    Response fields
    • itemslist of objectsRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired

        A thread message's thread title; otherwise the sent title, or the body's first line when the message was sent without one.

      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • matchobject

        In a search result for a thread, the message that matched, when it's an earlier message in the thread rather than the latest.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
      • previousMessageobject

        For a message in a thread, the message before it. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

    • totalinteger · at least 0Required

      How many messages match the filters, across all pages.

    • nextCursorstring · can be nullRequired

      Pass this as cursor to get the next page. null on the last page.

  • 400

    in isn't all, archive or snoozed (invalid_place), unread isn't true or false (invalid_unread_filter), or the cursor came from a different list (invalid_cursor)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 404

    The source was not found (not_found)

  • 503

    Search is at capacity (search_busy), the search took too long (search_timeout), or Ripple is busy (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages \
  -H "Authorization: Bearer $RIPPLE_KEY"
{
  "items": [
    {
      "messageId": "msg_2fe56d9f692c4febb604bb2c2c884ae7",
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "title": "Release progress",
      "preview": "Build completed.",
      "alert": "standard",
      "link": null,
      "firstReceivedAt": "2026-10-03T13:31:07.219Z",
      "receivedAt": "2026-10-03T13:31:07.219Z",
      "updatedAt": "2026-10-03T13:31:07.219Z",
      "readAt": null,
      "archivedAt": null,
      "revision": 1,
      "snooze": null,
      "thread": {
        "id": "thr_e91d5ec03ea9489d89a302645ccca63b",
        "title": "Release progress",
        "latestMessageId": "msg_2fe56d9f692c4febb604bb2c2c884ae7",
        "latestMessageNumber": 1,
        "messageCount": 1,
        "lastSeenMessageNumber": 0,
        "unseenMessageCount": 1,
        "firstUnseenMessageNumber": 1,
        "manuallyUnread": false,
        "createdAt": "2026-10-03T13:31:07.219Z",
        "updatedAt": "2026-10-03T13:31:07.219Z"
      }
    },
    {
      "messageId": "msg_0575320416fe4544b646044392618fbd",
      "source": {
        "kind": "system",
        "id": "src_9fddbdcb785848c6b10b068facd32d87",
        "label": "Inbox"
      },
      "title": "Deployment complete",
      "preview": "Version 1.2 is ready.",
      "alert": "standard",
      "link": null,
      "firstReceivedAt": "2026-10-03T13:31:07.201Z",
      "receivedAt": "2026-10-03T13:31:07.201Z",
      "updatedAt": "2026-10-03T13:31:07.201Z",
      "readAt": null,
      "archivedAt": null,
      "revision": 1,
      "snooze": null
    }
  ],
  "total": 2,
  "nextCursor": null
}

Watch for new messages

GET/v1/messages/stream

Keeps the connection open and sends each new message as it arrives, as Server-Sent Events. A new message is one Ripple accepts, including a new message in a thread; reading, archiving, snoozing, moving and Trash send nothing. Each message event's data is one line of JSON: the message as GET /v1/messages/{messageId} describes a message, but always the one that arrived, without sourceState or sourceDeletedAt. A connection starts at the present. Every event has an id; reconnect with the last one in Last-Event-ID to receive every new message after it, for up to 30 days. An id with no data moves your place forward without a message. A comment line every 15 seconds keeps the connection open. The connection can close at any time, for example after 15 minutes, so reconnect when it does. Ignore events with other names.

AuthAPI token

Query parameters

  • sourceIdstring · starts with src_

    A source ID, for only that source's messages. Use Inbox's ID, from GET /v1/sources, for Inbox. Leave it out for every source.

Headers

  • Last-Event-IDstring

    The id of the last event received, to resume after it. Leave it out to start at the present.

Responses

  • 200

    An open stream of new messages

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 404

    The source was not found (not_found)

  • 410

    Last-Event-ID is more than 30 days old or isn't one Ripple sent to this account (last_event_id_expired). Reconnect without it, and list messages to catch up.

  • 429

    The account has too many streams open (message_stream_limit). Retry after the indicated delay.

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages/stream \
  -H "Authorization: Bearer $RIPPLE_KEY"
"id: AQ2zvT3fX0Rk8yq1c8h0b2NtJ4kT3PnRj6UeB-wJ2pYc1nq9Vd0aXg2nN4lD7c0F\nevent: message\ndata: {\"messageId\":\"msg_2fe56d9f692c4febb604bb2c2c884ae7\",\"source\":{\"kind\":\"custom\",\"id\":\"src_aa960551ca5b4ec68f82747db1f75a3b\",\"label\":\"Deploy notifications\"},\"title\":\"Deploy failed\",\"body\":\"Tests failed on main.\",\"link\":null,\"linkTitle\":null,\"alert\":\"important\",\"sound\":null,\"firstReceivedAt\":\"2026-10-03T13:31:07.219Z\",\"receivedAt\":\"2026-10-03T13:31:07.219Z\",\"updatedAt\":\"2026-10-03T13:31:07.219Z\",\"readAt\":null,\"archivedAt\":null,\"revision\":1,\"snooze\":null}\n\n: keep-alive\n"

Read a message

GET/v1/messages/{messageId}

Returns a message and its history in timeline. For a message in a thread, message shows the thread's latest state, requestedMessage names the message you asked for, and timeline holds the thread's newest messages.

To read further back, pass timelineCursor as cursor to GET /v1/threads/{threadId}. To jump to the page that ends at the message you asked for, pass requestedMessage.cursor instead.

AuthAPI token

Path parameters

  • messageIdstringRequired

Responses

  • 200

    The message and its timeline

    Response fields
    • messageobjectRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestringRequired

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be nullRequired
    • requestedMessageobject

      The message you asked for, when it's in a thread. message still shows the thread's latest state.

      Fields
      • messageIdstringRequired
      • messageNumberinteger · at least 1Required
      • cursorstringRequired

        Pass this as cursor to GET /v1/threads/{threadId} for the page that ends at this message: the message, the ones before it, and a nextCursor to keep going.

    • timelinelist of objectsRequired
      Fields
      • eventIdstringRequired
      • eventTypestringRequired

        acceptedreadunreadarchivedunarchiveddeletedrestoredsource_changedsnoozedsnooze_changedsnooze_canceledalert_changed

      • createdAtstring · date and timeRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • messageIdstring
      • messageNumberinteger · at least 1
      • titlestring · can be null
      • bodystring · can be null
      • linkstring · URL · can be null
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be null

        quietstandardimportant

      • metadataobject · can be nullRequired
        Fields
        • threadTitlestring · can be null

          The thread's title when the message arrived, or null for a message that isn't in a thread.

        • snoozeIdstring
        • generationinteger · at least 1
        • returnAtstring · date and time
        • timeZonestring
        • previousReturnAtstring · date and time
        • previousTimeZonestring
        • alertstring

          quietstandardimportant

        • fromstring · can be null

          quietstandardimportant

        • tostring

          quietstandardimportant

        • fromSourceobject

          The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

          Fields
          • kindstringRequired

            systemcustom

          • idstring · starts with src_Required
          • labelstringRequired
        • toSourceobject

          The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

          Fields
          • kindstringRequired

            systemcustom

          • idstring · starts with src_Required
          • labelstringRequired
    • timelineCursorstring · can be nullRequired

      Pass this as cursor to GET /v1/threads/{threadId} to read further back than timeline goes. null when timeline already holds the whole thread, or the message isn't in a thread.

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 404

    The message was not found (not_found)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages/MESSAGE_ID \
  -H "Authorization: Bearer $RIPPLE_KEY"
{
  "message": {
    "messageId": "msg_0575320416fe4544b646044392618fbd",
    "source": {
      "kind": "custom",
      "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
      "label": "Deploy notifications"
    },
    "title": "Deployment complete",
    "preview": "Version 1.2 is ready.",
    "body": "Version 1.2 is ready.",
    "link": null,
    "linkTitle": null,
    "alert": "standard",
    "firstReceivedAt": "2026-10-03T13:31:07.201Z",
    "receivedAt": "2026-10-03T13:31:07.201Z",
    "updatedAt": "2026-10-03T13:31:07.201Z",
    "readAt": null,
    "archivedAt": null,
    "revision": 3,
    "snooze": null,
    "sourceDeletedAt": null,
    "sourceState": "active"
  },
  "timeline": [
    {
      "eventId": "evt_b962b25063584cfaa75c3510f94d23b3",
      "eventType": "unarchived",
      "createdAt": "2026-10-03T13:31:07.328Z",
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "metadata": null,
      "messageId": "msg_0575320416fe4544b646044392618fbd"
    },
    {
      "eventId": "evt_2d808a8cfc3543d7a350f8e7fbade900",
      "eventType": "archived",
      "createdAt": "2026-10-03T13:31:07.315Z",
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "metadata": null,
      "messageId": "msg_0575320416fe4544b646044392618fbd"
    },
    {
      "eventId": "evt_51c8563239c544609b7e08f6dc319ac8",
      "eventType": "accepted",
      "createdAt": "2026-10-03T13:31:07.201Z",
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "metadata": {
        "alert": "standard",
        "threadTitle": null
      },
      "messageId": "msg_0575320416fe4544b646044392618fbd"
    }
  ],
  "timelineCursor": null
}

Mark messages read

POST/v1/messages/read

Marks up to 100 messages read, all or none. A message in a thread marks its whole thread.

AuthAPI token

Body

  • messageIdslist of strings · 1–100 itemsRequired

Responses

  • 200

    The selected messages as they are now

    Response fields
    • messageslist of objectsRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestring

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be null
    • changedCountinteger · at least 0Required
    • mutationAtstring · date and timeRequired
  • 400

    messageIds is missing or empty, or has more than 100 IDs (invalid_message_ids)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 403

    The API token is read-only (read_only_token), so it can only list, read and search.

  • 404

    One of the messages was not found (not_found)

  • 409

    A message the request names, or its source, is in Trash (message_deleted)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages/read \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messageIds": [
      "msg_0575320416fe4544b646044392618fbd"
    ]
  }'
{
  "messages": [
    {
      "messageId": "msg_0575320416fe4544b646044392618fbd",
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "title": "Deployment complete",
      "preview": "Version 1.2 is ready.",
      "body": "Version 1.2 is ready.",
      "link": null,
      "linkTitle": null,
      "alert": "standard",
      "firstReceivedAt": "2026-10-03T13:31:07.201Z",
      "receivedAt": "2026-10-03T13:31:07.201Z",
      "updatedAt": "2026-10-03T13:31:07.201Z",
      "readAt": "2026-10-03T13:31:07.280Z",
      "archivedAt": null,
      "revision": 1,
      "snooze": null,
      "sourceDeletedAt": null,
      "sourceState": "active"
    }
  ],
  "changedCount": 1,
  "mutationAt": "2026-10-03T13:31:07.280Z"
}

Mark messages unread

POST/v1/messages/unread

Marks up to 100 messages unread, all or none. A message in a thread marks its whole thread.

AuthAPI token

Body

  • messageIdslist of strings · 1–100 itemsRequired

Responses

  • 200

    The selected messages as they are now

    Response fields
    • messageslist of objectsRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestring

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be null
    • changedCountinteger · at least 0Required
    • mutationAtstring · date and timeRequired
  • 400

    messageIds is missing or empty, or has more than 100 IDs (invalid_message_ids)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 403

    The API token is read-only (read_only_token), so it can only list, read and search.

  • 404

    One of the messages was not found (not_found)

  • 409

    A message the request names, or its source, is in Trash (message_deleted)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages/unread \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messageIds": [
      "msg_0575320416fe4544b646044392618fbd"
    ]
  }'
{
  "messages": [
    {
      "messageId": "msg_0575320416fe4544b646044392618fbd",
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "title": "Deployment complete",
      "preview": "Version 1.2 is ready.",
      "body": "Version 1.2 is ready.",
      "link": null,
      "linkTitle": null,
      "alert": "standard",
      "firstReceivedAt": "2026-10-03T13:31:07.201Z",
      "receivedAt": "2026-10-03T13:31:07.201Z",
      "updatedAt": "2026-10-03T13:31:07.201Z",
      "readAt": null,
      "archivedAt": null,
      "revision": 1,
      "snooze": null,
      "sourceDeletedAt": null,
      "sourceState": "active"
    }
  ],
  "changedCount": 1,
  "mutationAt": "2026-10-03T13:31:07.300Z"
}

Archive messages

POST/v1/messages/archive

Archives up to 100 messages, all or none. Archiving a snoozed message ends its snooze.

AuthAPI token

Body

  • messageIdslist of strings · 1–100 itemsRequired

Responses

  • 200

    The selected messages as they are now

    Response fields
    • messageslist of objectsRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestring

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be null
    • changedCountinteger · at least 0Required
    • mutationAtstring · date and timeRequired
  • 400

    messageIds is missing or empty, or has more than 100 IDs (invalid_message_ids)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 403

    The API token is read-only (read_only_token), so it can only list, read and search.

  • 404

    One of the messages was not found (not_found)

  • 409

    A message the request names, or its source, is in Trash (message_deleted)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages/archive \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messageIds": [
      "msg_0575320416fe4544b646044392618fbd"
    ]
  }'
{
  "messages": [
    {
      "messageId": "msg_0575320416fe4544b646044392618fbd",
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "title": "Deployment complete",
      "preview": "Version 1.2 is ready.",
      "body": "Version 1.2 is ready.",
      "link": null,
      "linkTitle": null,
      "alert": "standard",
      "firstReceivedAt": "2026-10-03T13:31:07.201Z",
      "receivedAt": "2026-10-03T13:31:07.201Z",
      "updatedAt": "2026-10-03T13:31:07.201Z",
      "readAt": null,
      "archivedAt": "2026-10-03T13:31:07.315Z",
      "revision": 2,
      "snooze": null,
      "sourceDeletedAt": null,
      "sourceState": "active"
    }
  ],
  "changedCount": 1,
  "mutationAt": "2026-10-03T13:31:07.315Z"
}

Unarchive messages

POST/v1/messages/unarchive

Unarchives up to 100 messages, all or none. Each message keeps its source, so it goes back to All Messages (in=all) and its own source, and to Inbox only if Inbox is its source.

AuthAPI token

Body

  • messageIdslist of strings · 1–100 itemsRequired

Responses

  • 200

    The selected messages as they are now

    Response fields
    • messageslist of objectsRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestring

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be null
    • changedCountinteger · at least 0Required
    • mutationAtstring · date and timeRequired
  • 400

    messageIds is missing or empty, or has more than 100 IDs (invalid_message_ids)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 403

    The API token is read-only (read_only_token), so it can only list, read and search.

  • 404

    One of the messages was not found (not_found)

  • 409

    A message the request names, or its source, is in Trash (message_deleted)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages/unarchive \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messageIds": [
      "msg_0575320416fe4544b646044392618fbd"
    ]
  }'
{
  "messages": [
    {
      "messageId": "msg_0575320416fe4544b646044392618fbd",
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "title": "Deployment complete",
      "preview": "Version 1.2 is ready.",
      "body": "Version 1.2 is ready.",
      "link": null,
      "linkTitle": null,
      "alert": "standard",
      "firstReceivedAt": "2026-10-03T13:31:07.201Z",
      "receivedAt": "2026-10-03T13:31:07.201Z",
      "updatedAt": "2026-10-03T13:31:07.201Z",
      "readAt": null,
      "archivedAt": null,
      "revision": 3,
      "snooze": null,
      "sourceDeletedAt": null,
      "sourceState": "active"
    }
  ],
  "changedCount": 1,
  "mutationAt": "2026-10-03T13:31:07.328Z"
}

Move messages to Trash

POST/v1/messages/trash

Moves up to 100 messages to Trash, all or none. You can restore them for 30 days; after that they're deleted forever. A message in a thread moves its whole thread. A message already in Trash is skipped and not counted.

AuthAPI token

Body

  • messageIdslist of strings · 1–100 itemsRequired

Responses

  • 200

    The messages this request moved to Trash

    Response fields
    • resultslist of objectsRequired

      Each message this request moved to Trash, with its thread's ID when it belongs to one.

      Fields
      • messageIdstringRequired
      • threadIdstring · can be nullRequired
    • changedCountinteger · at least 0Required

      How many messages and threads this request moved to Trash. Ones already there aren't counted.

    • mutationAtstring · date and timeRequired
  • 400

    messageIds is missing or empty, or has more than 100 IDs (invalid_message_ids)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 403

    The API token is read-only (read_only_token), so it can only list, read and search.

  • 404

    One of the messages was not found (not_found)

  • 409

    A selected message's source is in Trash (message_deleted)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages/trash \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "messageIds": [
      "msg_0575320416fe4544b646044392618fbd"
    ]
  }'
{
  "results": [
    {
      "messageId": "msg_2fe56d9f692c4febb604bb2c2c884ae7",
      "threadId": "thr_e91d5ec03ea9489d89a302645ccca63b"
    }
  ],
  "changedCount": 1,
  "mutationAt": "2026-10-03T13:31:07.788Z"
}

Search messages

POST/v1/messages/search

Searches the titles, bodies, thread titles and source names of messages in every source. Active, archived and snoozed messages are included; Trash is not. A thread shows up once, at its best-matching message. Results rank by how well they match (an exact title first, then the whole query together in one field, then every word in one field), then newest first by receivedAt.

Filters narrow results by place, read state, source, alert and date, and work without a query. When a word matches nothing, Ripple also tries one-letter corrections taken only from your own messages and lists them in corrections. For the next page, pass nextCursor as cursor; new messages can shift results between pages.

AuthAPI token

Body

  • instring

    allarchivesnoozed

    Searches one place only: all for All Messages (neither archived nor snoozed), archive for archived messages, or snoozed for messages waiting to come back. A thread is where the thread is, whichever of its messages matched. Leave it out to search everywhere except Trash.

  • querystring · up to 500 characters

    The words to search for, up to 64. Every word must match, and the last can be the start of a word, so depl finds deploy. Put the whole query in double quotes to find the words together in one field. Words with digits or symbols, such as IDs, paths and percentages, match exactly. Typo correction only runs on unquoted searches of 12 words or fewer. Leave it out or blank to get everything the filters allow, newest first.

  • unreadboolean

    true finds only unread messages and false only read ones. Leave it out for both. A thread is read or unread as a whole, as its result's readAt shows, whichever of its messages matched.

  • sourceIdslist of strings · 1–100 items

    Searches only these sources, by ID. Use Inbox's ID for Inbox.

  • afterstring · date and time

    Finds only messages whose receivedAt is at or after this time.

  • beforestring · date and time

    Finds only messages whose receivedAt is before this time. If you also send after, this must be later.

  • sortstring

    relevancenewest

    relevance, the default, ranks by how well each result matches, then newest first by receivedAt. newest sorts by receivedAt alone and places a thread at its newest matching message. A search without a query is always newest first.

  • alertstring

    quietstandardimportant

    Finds only messages whose alert is now this one. Messages sent without an alert count as standard.

  • limitinteger · 1–100 · default 50

    The most results to return in one page.

  • cursorstring · 1–200 characters

    The nextCursor from the previous page. Keep the query and filters the same.

Responses

  • 200

    One page of ranked results

    Response fields
    • itemslist of objectsRequired
      Fields
      • messageobjectRequired

        The matching message as it appears in lists. For a thread, this is the thread's latest message, and match names the earlier message that matched, if it wasn't the latest.

        Fields
        • messageIdstringRequired
        • sourceobjectRequired

          The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

          Fields
          • kindstringRequired

            systemcustom

          • idstring · starts with src_Required
          • labelstringRequired
        • titlestring · can be nullRequired

          A thread message's thread title; otherwise the sent title, or the body's first line when the message was sent without one.

        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

        • soundstring · can be null

          hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

          The sound the sender chose for this message. Null when it plays its source's sound or the account's.

        • linkstring · URL · can be nullRequired
        • linkTitlestring · up to 64 characters · can be null
        • firstReceivedAtstring · date and timeRequired

          When Ripple first received the message. It never changes.

        • receivedAtstring · date and timeRequired

          The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

        • updatedAtstring · date and timeRequired
        • revisioninteger · at least 1Required

          Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

        • snoozeobject · can be nullRequired
          Fields
          • snoozeIdstringRequired
          • returnAtstring · date and timeRequired
          • timeZonestringRequired
          • alertstringRequired

            quietstandardimportant

          • generationinteger · at least 1Required
          • createdAtstring · date and timeRequired
          • updatedAtstring · date and timeRequired
        • readAtstring · date and time · can be null
        • archivedAtstring · date and time · can be null
        • threadobject
          Fields
          • idstring · starts with thr_Required
          • titlestring · up to 120 charactersRequired
          • latestMessageIdstringRequired
          • latestMessageNumberinteger · at least 1Required
          • messageCountinteger · at least 1Required
          • lastSeenMessageNumberinteger · at least 0Required
          • unseenMessageCountinteger · at least 0Required
          • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
          • manuallyUnreadbooleanRequired
          • createdAtstring · date and timeRequired
          • updatedAtstring · date and timeRequired
        • matchobject

          In a search result for a thread, the message that matched, when it's an earlier message in the thread rather than the latest.

          Fields
          • messageIdstringRequired
          • messageNumberinteger · at least 1Required
        • previousMessageobject

          For a message in a thread, the message before it. Present only when the thread has an earlier message.

          Fields
          • messageIdstringRequired
          • messageNumberinteger · at least 1Required
          • previewstringRequired

            The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

          • alertstring · can be nullRequired

            quietstandardimportant

      • excerptobjectRequired

        Plain text from the matching message's body, around the first match. It never contains markup.

        Fields
        • textstringRequired
        • truncatedStartbooleanRequired
        • truncatedEndbooleanRequired
    • nextCursorstring · can be nullRequired

      Pass this as cursor for the next page. It's null when there are no more matches, or when the search has reached its limit: one search returns at most 1,000 results plus one page. Check truncated before you treat the results as complete.

    • truncatedbooleanRequired

      true when more matches exist but the search can't return another page, so nextCursor is null. Narrow the query or filters to reach them. false doesn't mean you have everything while nextCursor is still set. This is separate from coverage.

    • correctionslist of objectsRequired
      Fields
      • originalstringRequired
      • alternativeslist of strings · 1–4 itemsRequired
    • coveragestringRequired

      completeindexing

      indexing while Ripple is building or rebuilding the search index, so results cover only the messages indexed so far. complete means every message is indexed. It says nothing about the result limit; check truncated for that.

  • 400

    The request is malformed or its filters conflict (invalid_search_request), the cursor came from a different search (invalid_cursor), or the query has more than 64 words (too_many_terms)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 503

    Search is at capacity (search_busy), the search took too long (search_timeout), or Ripple is busy (database_busy). Wait the number of seconds in Retry-After, then try again.

Example
curl https://api.ripplepush.com/v1/messages/search \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "query": "Deployment"
  }'
{
  "items": [],
  "nextCursor": null,
  "truncated": false,
  "corrections": [],
  "coverage": "complete"
}

Move messages between sources

POST/v1/messages/move

Moves up to 100 messages to other sources, all or none. Each message keeps its ID, history, read and archive state and snooze. A message already in its target source comes back with changed: false and adds nothing to its history. Messages in threads stay with their thread's source and can't be moved.

AuthAPI token

Body

  • moveslist of objects · 1–100 itemsRequired
    Fields
    • messageIdstringRequired
    • sourceIdstring · starts with src_Required

Responses

  • 200

    The messages as they are after the move

    Response fields
    • messageslist of objectsRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestring

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be null
    • resultslist of objectsRequired
      Fields
      • messageIdstringRequired
      • fromSourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • toSourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • changedbooleanRequired
    • changedCountinteger · at least 0Required
    • mutationAtstring · date and timeRequired
  • 400

    moves is missing or malformed, names a message twice, or has more than 100 entries (invalid_message_moves)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 403

    The API token is read-only (read_only_token), so it can only list, read and search.

  • 404

    A selected message or target source was not found (not_found)

  • 409

    A selected message is in Trash (message_deleted) or belongs to a thread (thread_move_not_supported)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/messages/move \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "moves": [
      {
        "messageId": "msg_0575320416fe4544b646044392618fbd",
        "sourceId": "src_65ab57d4851f4e828dad9e4c29ea0f48"
      }
    ]
  }'
{
  "messages": [
    {
      "messageId": "msg_0575320416fe4544b646044392618fbd",
      "source": {
        "kind": "custom",
        "id": "src_65ab57d4851f4e828dad9e4c29ea0f48",
        "label": "Finished builds"
      },
      "title": "Deployment complete",
      "preview": "Version 1.2 is ready.",
      "body": "Version 1.2 is ready.",
      "link": null,
      "linkTitle": null,
      "alert": "quiet",
      "firstReceivedAt": "2026-10-03T13:31:07.201Z",
      "receivedAt": "2026-10-03T13:31:07.201Z",
      "updatedAt": "2026-10-03T13:31:07.201Z",
      "readAt": null,
      "archivedAt": null,
      "revision": 8,
      "snooze": null,
      "sourceDeletedAt": null,
      "sourceState": "active"
    }
  ],
  "results": [
    {
      "messageId": "msg_0575320416fe4544b646044392618fbd",
      "fromSource": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "toSource": {
        "kind": "custom",
        "id": "src_65ab57d4851f4e828dad9e4c29ea0f48",
        "label": "Finished builds"
      },
      "changed": true
    }
  ],
  "changedCount": 1,
  "mutationAt": "2026-10-03T13:31:07.445Z"
}

Snooze a message

PUT/v1/messages/{messageId}/snooze

Takes a message out of All Messages until returnAt, then brings it back. If the message is already snoozed, this replaces its snooze. You can also choose the time zone, the alert it comes back with, and an expectedRevision so the snooze applies only to the version you read.

AuthAPI token

Path parameters

  • messageIdstringRequired

Body

  • returnAtstring · date and timeRequired

    The exact time the message comes back, such as 2026-10-03T14:31:07Z. Ripple doesn't read phrases like tomorrow at 9, so work out the time before you send it.

  • timeZonestring · 1–255 characters

    An IANA time zone, such as America/New_York, kept for showing and editing the snooze. If you leave it out, a replaced snooze keeps its zone. Otherwise Ripple uses the account's time zone if it has one (it keeps one while quiet hours are on), or UTC.

  • alertstring

    quietstandardimportant

    The alert the message comes back with. If you leave it out, a replaced snooze keeps its alert. Otherwise an important message comes back important and any other comes back standard.

  • expectedRevisioninteger · at least 1

    The message's revision when you read it. If the message has changed since, the request fails with 409 message_changed. Leave it out to snooze the message as it is now.

Responses

  • 200

    The message with its snooze

    Response fields
    • messageobjectRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestring

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be null
  • 400

    The request is malformed (invalid_snooze_request), or its time zone (invalid_time_zone) or alert (invalid_alert) is not valid

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 403

    The API token is read-only (read_only_token), so it can only list, read and search.

  • 404

    The message was not found (not_found)

  • 409

    The message has changed since expectedRevision (message_changed, with the message as it is now in current), is in Trash (message_deleted) or is archived (message_archived)

  • 422

    returnAt has passed (snooze_time_in_past) or is more than 365 days away (snooze_time_too_far)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

Example
curl -X PUT https://api.ripplepush.com/v1/messages/MESSAGE_ID/snooze \
  -H "Authorization: Bearer $RIPPLE_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "returnAt": "2026-10-03T14:31:07.364Z"
  }'
{
  "message": {
    "messageId": "msg_0575320416fe4544b646044392618fbd",
    "source": {
      "kind": "custom",
      "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
      "label": "Deploy notifications"
    },
    "title": "Deployment complete",
    "preview": "Version 1.2 is ready.",
    "link": null,
    "linkTitle": null,
    "alert": "quiet",
    "firstReceivedAt": "2026-10-03T13:31:07.201Z",
    "receivedAt": "2026-10-03T13:31:07.201Z",
    "updatedAt": "2026-10-03T13:31:07.201Z",
    "readAt": null,
    "archivedAt": null,
    "revision": 6,
    "snooze": {
      "snoozeId": "snz_b4b4e9c6740d4c78b4b73e6115c1c335",
      "returnAt": "2026-10-03T14:31:07.364Z",
      "timeZone": "UTC",
      "alert": "quiet",
      "generation": 1,
      "createdAt": "2026-10-03T13:31:07.416Z",
      "updatedAt": "2026-10-03T13:31:07.416Z"
    },
    "body": "Version 1.2 is ready."
  }
}

Cancel a snooze

DELETE/v1/messages/{messageId}/snooze

Cancels a message's snooze. Its read state and alert stay as they are, and no notification is sent. Add expectedRevision to cancel only if the message hasn't changed since you read it. Send no body.

AuthAPI token

Path parameters

  • messageIdstringRequired

Query parameters

  • expectedRevisioninteger · at least 1

    The message's revision when you read it. If the message has changed since, the request fails with 409 message_changed.

Responses

  • 200

    The message, now without a snooze. You get this even if no snooze was left to cancel.

    Response fields
    • messageobjectRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestring

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be null
  • 400

    expectedRevision isn't a positive whole number (invalid_snooze_request), or the request has a body (unexpected_body)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 403

    The API token is read-only (read_only_token), so it can only list, read and search.

  • 404

    The message was not found (not_found)

  • 409

    The message has changed since expectedRevision (message_changed, with the message as it is now in current), is in Trash (message_deleted) or is archived (message_archived)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl -X DELETE https://api.ripplepush.com/v1/messages/MESSAGE_ID/snooze \
  -H "Authorization: Bearer $RIPPLE_KEY"
{
  "message": {
    "messageId": "msg_0575320416fe4544b646044392618fbd",
    "source": {
      "kind": "custom",
      "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
      "label": "Deploy notifications"
    },
    "title": "Deployment complete",
    "preview": "Version 1.2 is ready.",
    "link": null,
    "linkTitle": null,
    "alert": "quiet",
    "firstReceivedAt": "2026-10-03T13:31:07.201Z",
    "receivedAt": "2026-10-03T13:31:07.201Z",
    "updatedAt": "2026-10-03T13:31:07.201Z",
    "readAt": null,
    "archivedAt": null,
    "revision": 7,
    "snooze": null,
    "body": "Version 1.2 is ready."
  }
}

Read a thread

GET/v1/threads/{threadId}

Returns a thread, its latest message and a page of its messages, newest first, with what happened to them in activity. For the next page, pass nextCursor as cursor. From GET /v1/messages/{messageId}, pass its timelineCursor to continue past its timeline, or its requestedMessage.cursor for the page that ends at that message. A cursor from another thread returns invalid_cursor.

When two accounts are joined, some thread IDs are replaced. An old ID still finds the thread that replaced it, and its cursors work with either ID.

AuthAPI token

Path parameters

  • threadIdstring · starts with thr_Required

Query parameters

  • limitinteger · 1–100 · default 50

    The most items to return in one page.

  • cursorstring

    The nextCursor from the previous page. Keep the other filters the same.

Responses

  • 200

    The thread and one page of its messages

    Response fields
    • threadobjectRequired
      Fields
      • idstring · starts with thr_Required
      • titlestring · up to 120 charactersRequired
      • latestMessageIdstringRequired
      • latestMessageNumberinteger · at least 1Required
      • messageCountinteger · at least 1Required
      • lastSeenMessageNumberinteger · at least 0Required
      • unseenMessageCountinteger · at least 0Required
      • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
      • manuallyUnreadbooleanRequired
      • createdAtstring · date and timeRequired
      • updatedAtstring · date and timeRequired
    • latestMessageobjectRequired
      Fields
      • messageIdstringRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • previewstringRequired

        The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • firstReceivedAtstring · date and timeRequired

        When Ripple first received the message. It never changes.

      • receivedAtstring · date and timeRequired

        The message's date in lists. It starts as the time the message arrived and moves forward when the message comes back from a snooze.

      • updatedAtstring · date and timeRequired
      • revisioninteger · at least 1Required

        Goes up each time the message changes. Send it as expectedRevision to act only on the version you read.

      • snoozeobject · can be nullRequired
        Fields
        • snoozeIdstringRequired
        • returnAtstring · date and timeRequired
        • timeZonestringRequired
        • alertstringRequired

          quietstandardimportant

        • generationinteger · at least 1Required
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • readAtstring · date and time · can be null
      • archivedAtstring · date and time · can be null
      • threadobject
        Fields
        • idstring · starts with thr_Required
        • titlestring · up to 120 charactersRequired
        • latestMessageIdstringRequired
        • latestMessageNumberinteger · at least 1Required
        • messageCountinteger · at least 1Required
        • lastSeenMessageNumberinteger · at least 0Required
        • unseenMessageCountinteger · at least 0Required
        • firstUnseenMessageNumberinteger · at least 1 · can be nullRequired
        • manuallyUnreadbooleanRequired
        • createdAtstring · date and timeRequired
        • updatedAtstring · date and timeRequired
      • previousMessageobject

        For a message in a thread, the message before it, as in message lists. Present only when the thread has an earlier message.

        Fields
        • messageIdstringRequired
        • messageNumberinteger · at least 1Required
        • previewstringRequired

          The body as one line of plain text, without Markdown syntax or HTML tags, after a first line that repeats the title. Past 280 UTF-16 code units it ends with …. Empty when nothing follows the title.

        • alertstring · can be nullRequired

          quietstandardimportant

      • sourceStatestringRequired

        activetrashdeleted

      • sourceDeletedAtstring · date and time · can be nullRequired
    • messageslist of objectsRequired
      Fields
      • messageIdstringRequired
      • messageNumberinteger · at least 1Required
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • titlestring · can be nullRequired
      • bodystring · can be nullRequired
      • linkstring · URL · can be nullRequired
      • linkTitlestring · up to 64 characters · can be null
      • alertstring · can be nullRequired

        quietstandardimportant

      • soundstring · can be null

        hoparcadeclinkdropechoglowknockliftsparkleswooptickwave

        The sound the sender chose for this message. Null when it plays its source's sound or the account's.

      • receivedAtstring · date and timeRequired
    • activitylist of objectsRequired

      What happened to the messages on this page, such as archiving or snoozing. Marking them read or unread isn't included.

      Fields
      • eventIdstringRequired
      • eventTypestringRequired

        archivedunarchivedsnoozedsnooze_changedsnooze_canceledalert_changed

      • createdAtstring · date and timeRequired
      • sourceobjectRequired

        The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

        Fields
        • kindstringRequired

          systemcustom

        • idstring · starts with src_Required
        • labelstringRequired
      • messageIdstringRequired
      • messageNumberinteger · at least 1Required
      • metadataobject · can be nullRequired
        Fields
        • threadTitlestring · can be null

          The thread's title when the message arrived, or null for a message that isn't in a thread.

        • snoozeIdstring
        • generationinteger · at least 1
        • returnAtstring · date and time
        • timeZonestring
        • previousReturnAtstring · date and time
        • previousTimeZonestring
        • alertstring

          quietstandardimportant

        • fromstring · can be null

          quietstandardimportant

        • tostring

          quietstandardimportant

        • fromSourceobject

          The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

          Fields
          • kindstringRequired

            systemcustom

          • idstring · starts with src_Required
          • labelstringRequired
        • toSourceobject

          The source a message belongs to. Inbox is the built-in system source; sources you create are custom.

          Fields
          • kindstringRequired

            systemcustom

          • idstring · starts with src_Required
          • labelstringRequired
    • nextCursorstring · can be nullRequired

      Pass this as cursor for older messages. null on the last page.

  • 400

    The cursor came from a different list (invalid_cursor)

  • 401

    The request has no valid API token or sign-in (unauthorized)

  • 404

    The thread was not found (not_found)

  • 503

    Ripple is busy right now (database_busy). Wait the number of seconds in Retry-After, then try again.

curl https://api.ripplepush.com/v1/threads/thr_abc123 \
  -H "Authorization: Bearer $RIPPLE_KEY"
{
  "thread": {
    "id": "thr_e91d5ec03ea9489d89a302645ccca63b",
    "title": "Release progress",
    "latestMessageId": "msg_2fe56d9f692c4febb604bb2c2c884ae7",
    "latestMessageNumber": 1,
    "messageCount": 1,
    "lastSeenMessageNumber": 0,
    "unseenMessageCount": 1,
    "firstUnseenMessageNumber": 1,
    "manuallyUnread": false,
    "createdAt": "2026-10-03T13:31:07.219Z",
    "updatedAt": "2026-10-03T13:31:07.219Z"
  },
  "latestMessage": {
    "messageId": "msg_2fe56d9f692c4febb604bb2c2c884ae7",
    "source": {
      "kind": "custom",
      "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
      "label": "Deploy notifications"
    },
    "title": null,
    "preview": "Build completed.",
    "body": "Build completed.",
    "link": null,
    "linkTitle": null,
    "alert": "standard",
    "firstReceivedAt": "2026-10-03T13:31:07.219Z",
    "receivedAt": "2026-10-03T13:31:07.219Z",
    "updatedAt": "2026-10-03T13:31:07.219Z",
    "readAt": null,
    "archivedAt": null,
    "revision": 1,
    "snooze": null,
    "thread": {
      "id": "thr_e91d5ec03ea9489d89a302645ccca63b",
      "title": "Release progress",
      "latestMessageId": "msg_2fe56d9f692c4febb604bb2c2c884ae7",
      "latestMessageNumber": 1,
      "messageCount": 1,
      "lastSeenMessageNumber": 0,
      "unseenMessageCount": 1,
      "firstUnseenMessageNumber": 1,
      "manuallyUnread": false,
      "createdAt": "2026-10-03T13:31:07.219Z",
      "updatedAt": "2026-10-03T13:31:07.219Z"
    },
    "sourceDeletedAt": null,
    "sourceState": "active"
  },
  "messages": [
    {
      "messageId": "msg_2fe56d9f692c4febb604bb2c2c884ae7",
      "messageNumber": 1,
      "source": {
        "kind": "custom",
        "id": "src_aa960551ca5b4ec68f82747db1f75a3b",
        "label": "Deploy notifications"
      },
      "title": null,
      "body": "Build completed.",
      "link": null,
      "linkTitle": null,
      "alert": "standard",
      "receivedAt": "2026-10-03T13:31:07.219Z"
    }
  ],
  "activity": [],
  "nextCursor": null
}