Sources
Create sources, change their settings and manage their send keys.
- GETList sources
/v1/sources - POSTCreate a source
/v1/sources - GETRead a source
/v1/sources/{sourceId} - PATCHUpdate a source
/v1/sources/{sourceId} - DELETEMove a source to Trash
/v1/sources/{sourceId} - POSTMute a source
/v1/sources/{sourceId}/mute - POSTUnmute a source
/v1/sources/{sourceId}/unmute - POSTDisable a source
/v1/sources/{sourceId}/disable - POSTEnable a source
/v1/sources/{sourceId}/enable - POSTMark a source's messages read
/v1/sources/{sourceId}/read - POSTGet a source's send key
/v1/sources/{sourceId}/send-key - POSTReset a source's send key
/v1/sources/{sourceId}/send-key/reset
List sources
GET/v1/sources
Lists your sources with their settings and unread counts: Inbox first, then the rest from oldest to newest.
AuthAPI token
Responses
- 200
Your sources
Response fields
itemslist of objectsRequiredFields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequired
- 401
The request has no valid API token or sign-in (
unauthorized) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl https://api.ripplepush.com/v1/sources \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources", {
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="GET",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"items": [
{
"sourceId": "src_9fddbdcb785848c6b10b068facd32d87",
"label": "Inbox",
"kind": "system",
"status": "active",
"iconSymbol": "inbox",
"iconColor": null,
"imageUrl": null,
"unreadCount": 0,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": false,
"defaultAlert": null,
"defaultSound": null,
"defaultLink": null,
"mutedAt": null,
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": null,
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.176Z"
},
{
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"label": "Deploy notifications",
"kind": "custom",
"status": "active",
"iconSymbol": null,
"iconColor": "blue",
"imageUrl": null,
"unreadCount": 1,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 1,
"hasMessages": true,
"defaultAlert": null,
"defaultSound": null,
"defaultLink": null,
"mutedAt": null,
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": "2026-10-03T13:31:07.188Z",
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.188Z"
}
]
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}Your sources
Create a source
POST/v1/sources
Creates a source. Only label is required; the other settings can be set now or later. To send to it, get its key from POST /v1/. An account can have up to 100 sources, counting those in Trash but not Inbox, and can make 30 attempts a minute. Each call creates a new source, so a retry can make a duplicate.
AuthAPI token
Body
labelstringRequiredThe source's name, 1 to 64 characters after trimming whitespace at either end. Two sources can share a name, but none can be called Inbox, in any capitalization.
iconSymbolstring · up to 64 characters · can be nulliconColorstring · can be nullredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial. Leave it out on a new source to get a random one of the account's least-used colors, or send
nullfor a neutral tile. Must benullor left out when you setimageUrl, since setting an image clears it.imageUrlstring · up to 2,048 characters · can be nullAn
https:/URL for the source's image, or a/ /api/path for an image uploaded to Ripple. A new path must name an image this account uploaded; any other returnssource-images/ {imageId} 400 invalid_source.defaultAlertstring · can be nullquietstandardimportantThe alert messages get when they're sent without
alert.nullmeansstandard.defaultSoundstring · can be nullhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · up to 2,048 characters · can be nullAn
https:/link that messages get when they're sent without/ link.
Responses
- 201
The new source
Response fields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequiredcontrolsobjectRequiredFields
canMutebooleanRequiredcanUnmutebooleanRequiredcanDisablebooleanRequiredcanEnablebooleanRequiredcanDeletebooleanRequired
- 400
A setting isn't valid (
invalid_source) - 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. - 409
The account already has 100 sources, counting those in Trash (
source_limit_reached) - 429
Too many attempts to create a source this minute (
source_creation_rate_limited).Retry-Aftersays how many seconds until you can try again. - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl https://api.ripplepush.com/v1/sources \
-H "Authorization: Bearer $RIPPLE_KEY" \
-H "Content-Type: application/json" \
-d '{
"label": "GitHub Alerts"
}'const response = await fetch("https://api.ripplepush.com/v1/sources", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
label: "GitHub Alerts",
}),
});
console.log(response.status, await response.text());import json
import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources",
data=json.dumps({
"label": "GitHub Alerts",
}).encode(),
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
"Content-Type": "application/json",
},
method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_abc123",
"label": "GitHub Alerts",
"kind": "custom",
"status": "active",
"iconSymbol": null,
"iconColor": "teal",
"imageUrl": null,
"unreadCount": 0,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": false,
"defaultAlert": null,
"defaultSound": null,
"defaultLink": null,
"mutedAt": null,
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": null,
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.176Z",
"controls": {
"canMute": true,
"canUnmute": false,
"canDisable": true,
"canEnable": true,
"canDelete": true
}
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The new source
Read a source
GET/v1/sources/{sourceId}
Returns a source with its settings, counts and controls, which say what you can do with it right now.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Responses
- 200
The source
Response fields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequiredcontrolsobjectRequiredFields
canMutebooleanRequiredcanUnmutebooleanRequiredcanDisablebooleanRequiredcanEnablebooleanRequiredcanDeletebooleanRequired
- 401
The request has no valid API token or sign-in (
unauthorized) - 404
The source was not found (
not_found) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl https://api.ripplepush.com/v1/sources/src_abc123 \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123", {
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="GET",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"label": "Deploy notifications",
"kind": "custom",
"status": "active",
"iconSymbol": null,
"iconColor": "blue",
"imageUrl": null,
"unreadCount": 1,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": true,
"defaultAlert": null,
"defaultSound": null,
"defaultLink": null,
"mutedAt": null,
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": "2026-10-03T13:31:07.188Z",
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.188Z",
"controls": {
"canMute": true,
"canUnmute": false,
"canDisable": true,
"canEnable": true,
"canDelete": true
}
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}The source
Update a source
PATCH/v1/sources/{sourceId}
Changes only the settings you send. The rest stay as they are, even older values that today's limits wouldn't allow. To switch between an icon and an image, set the one you're replacing to null. Inbox's icon, color, image and defaults can change, but not its name.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Body
labelstringThe source's name, 1 to 64 characters after trimming whitespace at either end. Two sources can share a name, but none can be called Inbox, in any capitalization.
iconSymbolstring · up to 64 characters · can be nulliconColorstring · can be nullredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial. Leave it out on a new source to get a random one of the account's least-used colors, or send
nullfor a neutral tile. Must benullor left out when you setimageUrl, since setting an image clears it.imageUrlstring · up to 2,048 characters · can be nullAn
https:/URL for the source's image, or a/ /api/path for an image uploaded to Ripple. A new path must name an image this account uploaded; any other returnssource-images/ {imageId} 400 invalid_source.defaultAlertstring · can be nullquietstandardimportantThe alert messages get when they're sent without
alert.nullmeansstandard.defaultSoundstring · can be nullhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · up to 2,048 characters · can be nullAn
https:/link that messages get when they're sent without/ link.
Responses
- 200
The updated source
Response fields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequiredcontrolsobjectRequiredFields
canMutebooleanRequiredcanUnmutebooleanRequiredcanDisablebooleanRequiredcanEnablebooleanRequiredcanDeletebooleanRequired
- 400
A setting isn't valid (
invalid_source), or the request renames Inbox (built_in_source) - 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 source was not found (
not_found) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl -X PATCH https://api.ripplepush.com/v1/sources/src_abc123 \
-H "Authorization: Bearer $RIPPLE_KEY" \
-H "Content-Type: application/json" \
-d '{
"defaultAlert": "quiet",
"defaultSound": "glow",
"defaultLink": "https://example.com/builds"
}'const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
defaultAlert: "quiet",
defaultSound: "glow",
defaultLink: "https://example.com/builds",
}),
});
console.log(response.status, await response.text());import json
import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123",
data=json.dumps({
"defaultAlert": "quiet",
"defaultSound": "glow",
"defaultLink": "https://example.com/builds",
}).encode(),
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
"Content-Type": "application/json",
},
method="PATCH",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"label": "Deploy notifications",
"kind": "custom",
"status": "active",
"iconSymbol": null,
"iconColor": "blue",
"imageUrl": null,
"unreadCount": 1,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": true,
"defaultAlert": "quiet",
"defaultSound": "glow",
"defaultLink": "https://example.com/builds",
"mutedAt": null,
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": "2026-10-03T13:31:07.188Z",
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.479Z",
"controls": {
"canMute": true,
"canUnmute": false,
"canDisable": true,
"canEnable": true,
"canDelete": true
}
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The updated source
Move a source to Trash
DELETE/v1/sources/{sourceId}
Moves a source to Trash. You can restore it for 30 days; after that it's deleted forever. Its messages stay where they are unless you set deleteMessages=true, which moves each of them to Trash separately. Send no body.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Query parameters
deleteMessagesboolean · default falsetruealso moves the source's messages to Trash, each separately, keeping their archived state so a restore puts them back as they were.
Responses
- 200
The source is in Trash
Response fields
sourceIdstringRequireddeletedbooleanRequiredtruedeletedAtstring · date and timeRequiredpurgeAtstring · date and timeRequireddeletedMessageCountinteger · at least 0Required
- 400
deleteMessagesis neithertruenorfalse(invalid_delete_source_request), the request sent a body (unexpected_body), or the source is Inbox (built_in_source) - 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 source was not found (
not_found) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl -X DELETE https://api.ripplepush.com/v1/sources/src_abc123 \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123", {
method: "DELETE",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="DELETE",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"deleted": true,
"deletedAt": "2026-10-03T13:31:07.839Z",
"purgeAt": "2026-11-02T13:31:07.839Z",
"deletedMessageCount": 0
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The source is in Trash
Mute a source
POST/v1/sources/{sourceId}/mute
Stops browser notifications for the source's messages. Ripple still accepts and saves them. A notification still waiting to go out is dropped if it comes due while the source is muted. A snoozed message still comes back with the alert chosen when it was snoozed.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Responses
- 200
The muted source
Response fields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequiredcontrolsobjectRequiredFields
canMutebooleanRequiredcanUnmutebooleanRequiredcanDisablebooleanRequiredcanEnablebooleanRequiredcanDeletebooleanRequired
- 400
Inbox is built in and can't be muted or disabled (
built_in_source) - 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 source was not found (
not_found) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl -X POST https://api.ripplepush.com/v1/sources/src_abc123/mute \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123/mute", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123/mute",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"label": "Deploy notifications",
"kind": "custom",
"status": "muted",
"iconSymbol": null,
"iconColor": "blue",
"imageUrl": null,
"unreadCount": 1,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": true,
"defaultAlert": "quiet",
"defaultSound": "glow",
"defaultLink": "https://example.com/builds",
"mutedAt": "2026-10-03T13:31:07.488Z",
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": "2026-10-03T13:31:07.188Z",
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.488Z",
"controls": {
"canMute": false,
"canUnmute": true,
"canDisable": true,
"canEnable": true,
"canDelete": true
}
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The muted source
Unmute a source
POST/v1/sources/{sourceId}/unmute
Turns browser notifications back on for new messages from the source. Messages that arrived while it was muted don't notify later.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Responses
- 200
The unmuted source
Response fields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequiredcontrolsobjectRequiredFields
canMutebooleanRequiredcanUnmutebooleanRequiredcanDisablebooleanRequiredcanEnablebooleanRequiredcanDeletebooleanRequired
- 400
Inbox is built in and can't be muted or disabled (
built_in_source) - 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 source was not found (
not_found) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl -X POST https://api.ripplepush.com/v1/sources/src_abc123/unmute \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123/unmute", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123/unmute",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"label": "Deploy notifications",
"kind": "custom",
"status": "active",
"iconSymbol": null,
"iconColor": "blue",
"imageUrl": null,
"unreadCount": 1,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": true,
"defaultAlert": "quiet",
"defaultSound": "glow",
"defaultLink": "https://example.com/builds",
"mutedAt": null,
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": "2026-10-03T13:31:07.188Z",
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.496Z",
"controls": {
"canMute": true,
"canUnmute": false,
"canDisable": true,
"canEnable": true,
"canDelete": true
}
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The unmuted source
Disable a source
POST/v1/sources/{sourceId}/disable
Stops the source from receiving messages: new sends return 403 source_disabled. Its existing messages stay available. A browser notification still waiting to go out is dropped if it comes due while the source is disabled. A snoozed message still comes back with the alert chosen when it was snoozed.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Responses
- 200
The disabled source
Response fields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequiredcontrolsobjectRequiredFields
canMutebooleanRequiredcanUnmutebooleanRequiredcanDisablebooleanRequiredcanEnablebooleanRequiredcanDeletebooleanRequired
- 400
Inbox is built in and can't be muted or disabled (
built_in_source) - 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 source was not found (
not_found) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl -X POST https://api.ripplepush.com/v1/sources/src_abc123/disable \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123/disable", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123/disable",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"label": "Deploy notifications",
"kind": "custom",
"status": "disabled",
"iconSymbol": null,
"iconColor": "blue",
"imageUrl": null,
"unreadCount": 1,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": true,
"defaultAlert": "quiet",
"defaultSound": "glow",
"defaultLink": "https://example.com/builds",
"mutedAt": null,
"disabledAt": "2026-10-03T13:31:07.505Z",
"autoContainedUntil": null,
"lastMessageAt": "2026-10-03T13:31:07.188Z",
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.505Z",
"controls": {
"canMute": true,
"canUnmute": false,
"canDisable": false,
"canEnable": true,
"canDelete": true
}
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The disabled source
Enable a source
POST/v1/sources/{sourceId}/enable
Lets the source receive messages again. If it was also muted, it stays muted.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Responses
- 200
The enabled source
Response fields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequiredcontrolsobjectRequiredFields
canMutebooleanRequiredcanUnmutebooleanRequiredcanDisablebooleanRequiredcanEnablebooleanRequiredcanDeletebooleanRequired
- 400
Inbox is built in and can't be muted or disabled (
built_in_source) - 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 source was not found (
not_found) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl -X POST https://api.ripplepush.com/v1/sources/src_abc123/enable \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123/enable", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123/enable",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"label": "Deploy notifications",
"kind": "custom",
"status": "active",
"iconSymbol": null,
"iconColor": "blue",
"imageUrl": null,
"unreadCount": 1,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": true,
"defaultAlert": "quiet",
"defaultSound": "glow",
"defaultLink": "https://example.com/builds",
"mutedAt": null,
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": "2026-10-03T13:31:07.188Z",
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.515Z",
"controls": {
"canMute": true,
"canUnmute": false,
"canDisable": true,
"canEnable": true,
"canDelete": true
}
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The enabled source
Mark a source's messages read
POST/v1/sources/{sourceId}/read
Marks every unread message in the source read, leaving snoozed and archived messages as they are.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Responses
- 200
The source after its messages were marked read
Response fields
sourceobjectRequiredFields
sourceIdstring · starts with src_RequiredThe source's permanent ID, which
POST/v1/takes assend sourceand lists take assourceId.labelstringRequiredkindstringRequiredsystemcustomsystemfor Inbox, which every account has, andcustomfor sources you create.statusstringRequiredactivemuteddisabledWhether the source is muted or disabled. These are separate: a source that's both shows
disabled, and showsmutedagain once it's enabled.iconSymbolstring · can be nullRequirediconColorstring · can be nullRequiredredorangeyellowgreentealblueindigopurplepinkThe color of the source's icon tile, or of the tile showing its initial.
nulluses a neutral tile. AlwaysnullwhileimageUrlis set.imageUrlstring · can be nullRequiredThe source's image: an
https:/URL, or a/ /api/path for an image uploaded to Ripple.source-images/ {imageId} unreadCountinteger · at least 0RequiredHow many unread messages the source has, leaving out archived and snoozed ones. A thread counts once, however many messages it holds.
importantUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertimportantnow. A thread uses its latest message's alert.quietUnreadCountinteger · at least 0RequiredHow many of the messages in
unreadCounthave the alertquietnow. Messages sent without an alert count asstandard, so they're in neither this count norimportantUnreadCount.snoozedCountinteger · at least 0RequiredHow many of the source's messages are snoozed, read or unread. A thread counts once. Snoozed messages are left out of
unreadCount, and archived or deleted messages are never snoozed.hasMessagesbooleanRequiredtrueif the source has any messages outside Trash, including archived and snoozed ones.defaultAlertstring · can be nullRequiredquietstandardimportantdefaultSoundstring · can be nullRequiredhoparcadeclinkdropechoglowknockliftsparkleswooptickwaveThe sound this source's new messages play in Ripple unless a message names its own; null plays the account's sound. Turning sounds off in Ripple's settings silences every source.
defaultLinkstring · URL · starts with https:// · can be nullRequiredAn
https:/link that messages get when they're sent without/ link.mutedAtstring · date and time · can be nullRequireddisabledAtstring · date and time · can be nullRequiredautoContainedUntilstring · date and time · can be nullRequiredWhen the source's 15-minute pause for going over its send limit ends or ended. Until then, its sends return
429 source_rate_limited.nullif it has never been paused.lastMessageAtstring · date and time · can be nullRequiredWhen the source last received a message, or
nullif it never has. Moving, archiving or deleting messages doesn't change it, and a new message doesn't change the source'supdatedAt.createdAtstring · date and timeRequiredupdatedAtstring · date and timeRequiredcontrolsobjectRequiredFields
canMutebooleanRequiredcanUnmutebooleanRequiredcanDisablebooleanRequiredcanEnablebooleanRequiredcanDeletebooleanRequired
markedReadCountinteger · at least 0RequiredreadAtstring · date and timeRequired
- 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 source was not found (
not_found) - 503
Ripple is busy right now (
database_busy). Wait the number of seconds inRetry-After, then try again.
curl -X POST https://api.ripplepush.com/v1/sources/src_abc123/read \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123/read", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123/read",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"source": {
"sourceId": "src_aa960551ca5b4ec68f82747db1f75a3b",
"label": "Deploy notifications",
"kind": "custom",
"status": "active",
"iconSymbol": null,
"iconColor": "blue",
"imageUrl": null,
"unreadCount": 0,
"importantUnreadCount": 0,
"quietUnreadCount": 0,
"snoozedCount": 0,
"hasMessages": true,
"defaultAlert": "quiet",
"defaultSound": "glow",
"defaultLink": "https://example.com/builds",
"mutedAt": null,
"disabledAt": null,
"autoContainedUntil": null,
"lastMessageAt": "2026-10-03T13:31:07.188Z",
"createdAt": "2026-10-03T13:31:07.176Z",
"updatedAt": "2026-10-03T13:31:07.515Z",
"controls": {
"canMute": true,
"canUnmute": false,
"canDisable": true,
"canEnable": true,
"canDelete": true
}
},
"markedReadCount": 1,
"readAt": "2026-10-03T13:31:07.522Z"
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The source after its messages were marked read
Get a source's send key
POST/v1/sources/{sourceId}/send-key
Returns the key for sending to this source, creating it the first time you ask. The key can only send, and only to this source. sendAddress is the same key built into a URL, for tools that only let you set a URL.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Responses
- 200
The source's send key
Response fields
sourceIdstring · starts with src_Requiredkeystring · starts with rpl_send_RequiredSend it as
Authorization: Bearer <key>.sendAddressstring · URLRequiredPOSTto this URL to send without anAuthorizationheader.
- 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 source was not found (
not_found) - 409
Ripple can no longer show the saved key (
send_key_not_recoverable). Reset it to get a new one. - 503
Send keys aren't set up on this server (
send_key_encryption_not_configured), or Ripple is busy (database_busy). Fordatabase_busy, wait the number of seconds inRetry-After, then try again.
curl -X POST https://api.ripplepush.com/v1/sources/src_abc123/send-key \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123/send-key", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123/send-key",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_abc123",
"key": "rpl_send_3fTq9ZkLm2Wx8RbN4vYc7HdJ1sGpAe0Kf6Uo",
"sendAddress": "https://api.ripplepush.com/v1/send?key=rpl_send_3fTq9ZkLm2Wx8RbN4vYc7HdJ1sGpAe0Kf6Uo"
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The source's send key
Reset a source's send key
POST/v1/sources/{sourceId}/send-key/reset
Replaces the source's send key. The old key stops working immediately, so every tool that sends to this source needs the new one.
AuthAPI token
Path parameters
sourceIdstring · starts with src_Required
Responses
- 200
The source's new send key
Response fields
sourceIdstring · starts with src_Requiredkeystring · starts with rpl_send_RequiredSend it as
Authorization: Bearer <key>.sendAddressstring · URLRequiredPOSTto this URL to send without anAuthorizationheader.
- 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 source was not found (
not_found) - 503
Send keys aren't set up on this server (
send_key_encryption_not_configured), or Ripple is busy (database_busy). Fordatabase_busy, wait the number of seconds inRetry-After, then try again.
curl -X POST https://api.ripplepush.com/v1/sources/src_abc123/send-key/reset \
-H "Authorization: Bearer $RIPPLE_KEY"const response = await fetch("https://api.ripplepush.com/v1/sources/src_abc123/send-key/reset", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.RIPPLE_KEY}`,
},
});
console.log(response.status, await response.text());import os
import urllib.request
request = urllib.request.Request(
"https://api.ripplepush.com/v1/sources/src_abc123/send-key/reset",
headers={
"Authorization": "Bearer " + os.environ["RIPPLE_KEY"],
},
method="POST",
)
with urllib.request.urlopen(request, timeout=30) as response:
print(response.status, response.read().decode()){
"sourceId": "src_abc123",
"key": "rpl_send_8KcWq1RzT5mYn0BvX3gJ7pLd2FhUa9Se4Oi6",
"sendAddress": "https://api.ripplepush.com/v1/send?key=rpl_send_8KcWq1RzT5mYn0BvX3gJ7pLd2FhUa9Se4Oi6"
}{
"code": "unauthorized",
"message": "Send a valid API token, or sign in."
}{
"code": "read_only_token",
"message": "This API token can only read."
}The source's new send key