API
SDK API

On this page
- GET /api/v1
- GET /api/v1/sdk
- GET /api/v1/sdk/client-config
- POST /api/v1/sdk/deep-links
- POST /api/v1/sdk/subscribers
- GET /api/v1/sdk/subscribers/{subscriber}
- PATCH /api/v1/sdk/subscribers/{subscriber}
- GET /api/v1/sdk/subscribers/{subscriber}/notifications
- GET /api/v1/sdk/subscribers/{subscriber}/notifications/{notification}
- POST /api/v1/sdk/subscribers/{subscriber}/notifications/{notification}/open
- POST /api/v1/sdk/deliveries/{delivery}/click
- POST /api/v1/sdk/events
The generated reference at /docs/api lists every declared scenario. This file records the routes that exist.
GET /api/v1
- Auth: none.
- Name:
api.v1.show - Request: none.
- Response:
200API_READY.data.versionisv1.data.sdkis/api/v1/sdk.data.publicis/api/v1/public. Message: “Notifiable API v1 is available.” - Errors:
429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
GET /api/v1/sdk
- Auth: none.
- Name:
api.v1.sdk.show - Request: none.
- Response:
200API_READY.data.versionisv1. Message: “Notifiable API v1 is available.” - Errors:
429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
GET /api/v1/sdk/client-config
- Auth:
X-Notifiable-Keywith the app’s development or production public key. The matching key chooses the environment. - Name:
api.v1.sdk.client-config.show - Request: none.
- Response:
200CLIENT_CONFIG. Message: “The client configuration was found.”dataincludes only a configured side. Android is{ status, package_name }and, whenstatusisready,firebasewithapiKey,appId,projectId, andmessagingSenderId.statusispending,ready, orfailed. Android is omitted when the app has no package name. iOS is{ bundle_id }when the workspace Apple connection exists and the app has a bundle ID. Web is{ public_key }. Expo, and a cross-platform app with neither side saved, returnsdataas an empty object. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
POST /api/v1/sdk/deep-links
- Auth:
X-Notifiable-Keywith the app’s development or production public key. Either key saves the routes for that app. - Name:
api.v1.sdk.deep-links.store - Request: JSON
{ "links": [{ "path": string, "label": string }] }.linksis required and holds at most 50 routes.pathis the path or URL opened on tap, at most 200 characters, and unique in the list.labelis the name shown beside it, at most 80 characters. An empty list clears the stored routes. The list replaces whatever was stored before. - Response:
200DEEP_LINKS_SAVED. Message: “The deep links were saved.”data.linksis the stored list. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.422VALIDATION_FAILED, typevalidation_error, whenlinksis missing or a path or label is invalid.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
POST /api/v1/sdk/subscribers
- Auth:
X-Notifiable-Keywith the app’s development or production public key. The matching key chooses the environment. - Name:
api.v1.sdk.subscribers.store - Request: JSON body. Required:
device_id(install id, max 80),platform(ios,android,web),sdk(expo,react-native,flutter,swift,kotlin,web),permission(granted,denied,not_determined). Required whenpermissionisgranted:provider(apns,fcm,expo,web_push) andtoken(max 4096). Optional:external_id,anonymous_id,email,first_name,last_name(max 80, email max 255),attributes(object, up to 20 keys of text, number, boolean, or one nested object; keys max 40),tags(up to 20 strings, each max 80),device_model,device_manufacturer(max 80),device_ip,os_version,app_version,sdk_version,locale,language(max 40),timezone(max 80),country_code(ISO alpha-2, stored uppercase),prompted(boolean;truemeans the SDK finished asking and clears a pending prompt). The samedevice_idupdates the existing subscriber. - Response:
201SUBSCRIBER_SAVEDfor a new device.200SUBSCRIBER_SAVEDwhen thatdevice_idalready exists in the app and environment. Message: “The subscriber was saved.”datahasid,environment,platform,permission,sdk,provider,device_id,external_id,anonymous_id, andprompt_permission.prompt_permissionis true when this device should be asked for permission again. The push token is not returned. Sending the same permission on a later save does not clear that request. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.403SUBSCRIBER_LIMIT_REACHED, typeauthorization_error, when a new production subscriber would pass the workspace cap. Development is not capped. An update of an existing device is not capped.422VALIDATION_FAILED, typevalidation_error, when a field is missing or invalid.grantedwithout a token or provider fails here.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
GET /api/v1/sdk/subscribers/{subscriber}
- Auth:
X-Notifiable-Key, same as save. - Name:
api.v1.sdk.subscribers.show - Request: subscriber id in the path.
- Response:
200SUBSCRIBER_FETCHED. Message: “The subscriber was found.”datahas the same fields as save, includingprompt_permission. Nothing is written. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.404SUBSCRIBER_NOT_FOUND, typeresource_not_found, when the id is missing or belongs to another app or the other environment.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
PATCH /api/v1/sdk/subscribers/{subscriber}
- Auth:
X-Notifiable-Key, same as save. - Name:
api.v1.sdk.subscribers.update - Request: any subset of the save fields. At least one field is required. An omitted field stays as stored.
nullclears a nullable field such asexternal_idoremail. Settingpermissiontograntedrequirestokenandprovideron this call, or already stored on the subscriber.prompted: trueclears a pending permission prompt. A permission value that differs from the stored one also clears it. - Response:
200SUBSCRIBER_UPDATED. Message: “The subscriber was updated.”datahas the same fields as save. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.404SUBSCRIBER_NOT_FOUND, typeresource_not_found, when the id is missing or belongs to another app or the other environment.422VALIDATION_FAILED, typevalidation_error, when the body is empty or a field is invalid.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
GET /api/v1/sdk/subscribers/{subscriber}/notifications
- Auth:
X-Notifiable-Key, same as save. The matching key chooses the environment. - Name:
api.v1.sdk.subscribers.notifications.index - Request: optional
page(integer, minimum 1) and optionalopened(trueorfalse). Each page has 20 notifications.opened=falsereturns delivered rows that have not been opened.opened=truereturns rows that have been opened. - Response:
200NOTIFICATIONS_LISTED. Message: “The notifications were listed.”data.notificationsis that subscriber’s deliveries, newest first. Each item hasid,title,body,url,image_url,data,alert,status(pending,delivered,failed, orskipped),opened,opened_at, andcreated_at.data.page,data.per_page, anddata.totaldescribe the page. Campaign totals are not included. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.404SUBSCRIBER_NOT_FOUND, typeresource_not_found, when the subscriber is missing or belongs to another app or the other environment.422VALIDATION_FAILED, typevalidation_error, whenpageis not a positive integer.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
GET /api/v1/sdk/subscribers/{subscriber}/notifications/{notification}
- Auth:
X-Notifiable-Key, same as save. - Name:
api.v1.sdk.subscribers.notifications.show - Request: subscriber id and notification id in the path.
- Response:
200NOTIFICATION_FETCHED. Message: “The notification was found.”datahas the same fields as one inbox item, includingopenedandopened_at. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.404SUBSCRIBER_NOT_FOUND, typeresource_not_found, when the subscriber is missing or belongs to another app or the other environment.404NOTIFICATION_NOT_FOUND, typeresource_not_found, when that subscriber has no delivery for the notification.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
POST /api/v1/sdk/subscribers/{subscriber}/notifications/{notification}/open
- Auth:
X-Notifiable-Keywith the app’s development or production public key. The matching key chooses the environment. - Name:
api.v1.sdk.subscribers.notifications.open - Request: none.
- Response:
200NOTIFICATION_OPENED. Message: “The open was recorded.”data.idis the notification id. The first open setsopened_atand stores onenotification_openedevent for that subscriber and delivery. A second open does not change the first time and does not store another event. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.404SUBSCRIBER_NOT_FOUND, typeresource_not_found, when the subscriber is missing or belongs to another app or the other environment.404NOTIFICATION_NOT_FOUND, typeresource_not_found, when that subscriber has no delivered notification.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
POST /api/v1/sdk/deliveries/{delivery}/click
- Auth:
X-Notifiable-Keywith the app’s development or production public key. The matching key chooses the environment. - Name:
api.v1.sdk.deliveries.click - Request: none.
{delivery}is the id appended to the notification URL asopt. - Response:
200DELIVERY_CLICKED. Message: “The click was recorded.”data.idis the delivery id. The first click setsclicked_atand stores onenotification_clickedevent. A second click does not change the first time and does not store another event. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.404NOTIFICATION_NOT_FOUND, typeresource_not_found, when the delivery is missing, not delivered, or belongs to another app or the other environment.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
POST /api/v1/sdk/events
- Auth:
X-Notifiable-Keywith the app’s development or production public key. The matching key chooses the environment. - Name:
api.v1.sdk.events.store - Request: JSON body. Required:
name(max 80) andsubscriber_id. Optional:properties, an object of at most 20 values. A value is text (max 200), a number, a boolean, or null. - Response:
201EVENT_RECORDED. Message: “The event was recorded.”datahasid,name, andsubscriber_id. A saved automation for that event name sends only when this subscriber is in its segment. - Errors:
401INVALID_PUBLIC_KEY, typeauthentication_error, when the key is missing, unknown, reset, or belongs to a deleted app.404SUBSCRIBER_NOT_FOUND, typeresource_not_found, when the subscriber is missing or belongs to another app or the other environment.422VALIDATION_FAILED, typevalidation_error, when a field is missing or invalid.429RATE_LIMIT_EXCEEDED, typerate_limit_exceeded, when the caller exceeds 60 requests per minute from one IP.500SERVER_ERROR, typeserver_error, when the request fails unexpectedly. The body does not include the exception text.
Other /api/* failures use the same envelope. A missing route is 404 ROUTE_NOT_FOUND, type route_not_found. Invalid fields are 422 VALIDATION_FAILED, type validation_error, with error.details listing the field, rule code, and message. A missing model is 404 RESOURCE_NOT_FOUND, type resource_not_found, unless the action throws a more specific code such as SUBSCRIBER_NOT_FOUND.
The previous /api/v1/subscribers, /api/v1/events, /api/v1/client-config, /api/v1/deep-links, /api/v1/deliveries, and /api/v1/notifications paths are not kept. Server routes are documented with each feature and rendered in the Server group of /docs/api.
