API reference
Notify
One notification to one of your users, through push, SMS or email in your order, billed only on the channel that delivers it.
/v1/notifySend a notification
notifications:wNode.js SDKhonkio.notify.send()Tries each channel in order until one delivers: push (any device accepting it counts), then SMS, then email by default. A channel is skipped when the person has no way to be reached on it (no active device, no phone number, no email address), when it is off, and, in the default order, when the key may not send on it; each attempt is recorded with its reason. An SMS or email the channel refuses (consent, opt-out, suppression, sending limits, a pause, the balance) falls through to the next channel, exactly where /v1/messages or /v1/emails would refuse it. A push no device accepts falls through after the same wait of up to a minute a push with fallback.sms has. An email is delivered once the email service accepts it; one refused when it is dispatched (a pause that ended in failure, a suppression since, a lost domain) falls through, refunded. A failure reported after the carrier or the email service accepted it (a delivery receipt, a bounce, a later reject) does not fall through. An email whose call to the email service failed (SES_ERROR) counts as not delivered, is refunded and falls through, as an SMS the carrier never took does; an SMS whose carrier call timed out counts as delivered. A channel with no verdict for an hour fails the notification (NOTIFY_STUCK on that channel, the ones after it skipped notify_stuck); an email still queued (a pause, the daily cap) is left to finish, and if it then fails no other channel is tried. A refused or throttled SMS can leave a refunded failed message (/v1/messages) and fire message.failed, as the same send through /v1/messages would, even when email then delivers. Only the channel that delivers is billed, at its normal price; a channel that fell through costs nothing. A template is rendered once, when the notification is created; every channel sends that text. The person's contact points are read then too: a channel they could not be reached on at that moment is skipped (no_active_device, no_phone_number, no_email) even if one is added before its turn, and nothing is rendered or kept for it. What is kept for the channels that can reach the person is at most 2 MB, rendered: past that, 422 NOTIFY_CONTENT_TOO_LARGE. Answers 202 with the notification: delivered or failed when that was settled at once, pending while a push or an email is being sent. The key needs notifications write and recipients read, plus push, messages or emails write for each channel tried; with no channels given and none of the three, 403 FORBIDDEN. from.sms is checked as /v1/messages checks from (403 PHONE_NUMBER_NOT_OWNED, TOLL_FREE_NOT_VERIFIED, 422 MESSAGE_TOO_LONG...) when the person can be texted. The same Idempotency-Key returns the first notification, pending or not, with no second send; with a different body it is 409 IDEMPOTENCY_KEY_REUSED. Notifications follow the key's mode: a test key sends to and reads test profiles and notifications only, through each channel's test mode.
Requires notifications:w.
Parameters
| Parameter | Type | Description |
|---|---|---|
Idempotency-Keyheader | string |
|
Request body
One notification to one of your users: who, in which order of channels, and what.
| Field | Type | Description |
|---|---|---|
user_idrequired | string | Your own id for the person: their recipient profile (/v1/recipients) and the user_id their push devices are registered under.
|
channels | string[] | The order to try, each at most once: push, sms, email. The first that delivers ends it. Left out: push, sms, email, skipping any channel that is off or that the key may not send on. A channel named here that the key may not send on is 403 FORBIDDEN.
|
text | string | The text: the SMS, the push body and the email's plain text. Up to 1600 characters. Required unless you send a template.
|
title | string | The push title. Not with a template.
|
subject | string | The email subject. Required when email may be tried and the person has an email address, unless you send a template.
|
html | string | The email's HTML body. Optional: without it the email is plain text. |
template | string | A template's id or alias (/v1/templates), in place of text, title, subject and html: each channel sends its own part. A live key sends the published version, a test key the draft. In the default order a channel the template has no part for is skipped; named in channels, it is 422 TEMPLATE_CHANNEL_MISSING.
|
variables | object | Values for the template's variables. One with neither a value nor a fallback refuses the notification (422 EMAIL_TEMPLATE_VARIABLE_MISSING, details.keys). Only with template. |
language | string | en or fr: the template's language version, in place of the profile's language. A part that language lacks comes from the template's default language. Only with template.
|
from | object | The senders. 422 NOTIFY_SENDER_REQUIRED when a channel that will be tried can reach the person and has none. |
sms | string | One of your numbers, E.164, to text from.
|
email | string | An address on one of your verified domains. A template's default from address fills it when you leave it out.
|
push_app_id | string | The push app to send with. Optional when the account has exactly one.
|
is_commercial | boolean | Default false. True makes the email leg a commercial email, exactly as on /v1/emails: CASL consent on file is required and the unsubscribe footer is added. SMS keeps its own consent rules; push has no such flag.
|
Responses
202The notification: delivered or failed when settled at once, pending while a push or an email is being sent. A retry with the same Idempotency-Key answers the first notification as it stands.
Field Type Description idrequiredstring ntf_…
objectrequiredstring - One of: notification
user_idrequiredstring statusrequiredstring pending while a push is being sent; delivered once a channel took it; failed when every channel was skipped, refused or failed.
- One of: pending | delivered | failed
channelrequiredstring The channel that delivered it.
- One of: push | sms | email
- Can be null
message_idrequiredstring The SMS (/v1/messages) that delivered it.
- Can be null
email_idrequiredstring The email (/v1/emails) that delivered it.
- Can be null
push_idstring The push (/v1/push) that delivered it.
- Can be null
attempts[]requiredobject[] Each channel tried, in order.
channelrequiredstring - One of: push | sms | email
outcomerequiredstring delivered: the channel took it (a push any device accepted, an SMS the carrier took, an email the email service accepted). pending: a push or an email is being sent. skipped: the channel could not be tried (no device, phone number or email address; the channel off or not permitted to the key; no template part for it). refused: the channel refused the send, as its own endpoint would. failed: a push no device accepted, or an email refused when it was dispatched, a failed call to the email service (SES_ERROR) included (refunded); NOTIFY_STUCK when a channel had no verdict for an hour (an email still queued is left to finish; if it then fails, the channels after it are skipped notify_stuck and none is tried).
- One of: delivered | pending | skipped | refused | failed
reasonrequiredstring Why it was skipped, refused or failed: a lowercase reason (no_active_device, no_push_app, no_phone_number, no_email, no_sender, push_unavailable, push_disabled, email_unavailable, not_permitted, template_channel_missing, content_purged, notify_stuck) or the channel's own error code (e.g. OPT_OUT_BLOCKED, NO_CONSENT, EMAIL_SUPPRESSED, or ENCRYPTION_KEY_MISSING when the push app has require_encryption and none of the user's devices registered a key). Null otherwise.
- Can be null
livemoderequiredboolean created_atrequiredstring - Format: date-time
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403FORBIDDEN: the key lacks recipients read, a channel named in channels it may not send on (details.channel), or, with no channels given, every channel. Or the refusals /v1/messages gives a from it may not send from (PHONE_NUMBER_NOT_OWNED, PHONE_NUMBER_SUSPENDED, TOLL_FREE_NOT_VERIFIED).The standard error body.
- 404RECIPIENT_NOT_FOUND: no profile and no active push device for user_id in the calling key's mode. Or NOT_FOUND (details.resource template): no template with that id or alias.The standard error body.
- 409IDEMPOTENCY_KEY_REUSED: the Idempotency-Key was used for a different notification.The standard error body.
- 422VALIDATION_ERROR; NOTIFY_CONTENT_REQUIRED (no text and no template, or no subject when email may be tried: details.field, details.channel); NOTIFY_SENDER_REQUIRED (a channel that will be tried can reach the person but has no sender: details.channel); TEMPLATE_CHANNEL_MISSING (a channel named in channels, or every channel tried, has no template part: details.channel); NOTIFY_CONTENT_TOO_LARGE (what would be sent on the channels that can reach the person, rendered, is over 2 MB: details.bytes, details.limit); EMAIL_TEMPLATE_NOT_PUBLISHED; EMAIL_TEMPLATE_VARIABLE_MISSING (details.keys); MESSAGE_TOO_LONG or a content rule for the text, as /v1/messages answers them.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data: notification, error } = await honkio.notify.send({
userId: 'user_1042',
text: 'Your Acme code is 123456',
subject: 'Your Acme code',
from: { sms: '+1416XXXXXXX', email: 'hello@yourapp.ca' },
}, { idempotencyKey: 'login-code-1042-2026-11-03' })
if (error) throw new Error(error.message)
console.log(notification.id, notification.status, notification.channel)curl -X POST https://api.honkio.ca/v1/notify \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"user_id": "user_42"
}'/v1/notificationsList notifications
notifications:rNode.js SDKhonkio.notifications.list()Newest first. Notifications follow the key's mode: a test key sends to and reads test profiles and notifications only, through each channel's test mode.
Requires notifications:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
limitquery | string | 1 to 100. Default 50. |
cursorquery | string | next_cursor from the previous page. |
user_idquery | string | Only this user's notifications. |
statusquery | string | Only notifications in this state.
|
Responses
200A page of notifications in the calling key's mode, newest first.
Field Type Description data[]requiredobject[] idrequiredstring ntf_…
objectrequiredstring - One of: notification
user_idrequiredstring statusrequiredstring pending while a push is being sent; delivered once a channel took it; failed when every channel was skipped, refused or failed.
- One of: pending | delivered | failed
channelrequiredstring The channel that delivered it.
- One of: push | sms | email
- Can be null
message_idrequiredstring The SMS (/v1/messages) that delivered it.
- Can be null
email_idrequiredstring The email (/v1/emails) that delivered it.
- Can be null
push_idstring The push (/v1/push) that delivered it.
- Can be null
attempts[]requiredobject[] Each channel tried, in order.
channelrequiredstring - One of: push | sms | email
outcomerequiredstring delivered: the channel took it (a push any device accepted, an SMS the carrier took, an email the email service accepted). pending: a push or an email is being sent. skipped: the channel could not be tried (no device, phone number or email address; the channel off or not permitted to the key; no template part for it). refused: the channel refused the send, as its own endpoint would. failed: a push no device accepted, or an email refused when it was dispatched, a failed call to the email service (SES_ERROR) included (refunded); NOTIFY_STUCK when a channel had no verdict for an hour (an email still queued is left to finish; if it then fails, the channels after it are skipped notify_stuck and none is tried).
- One of: delivered | pending | skipped | refused | failed
reasonrequiredstring Why it was skipped, refused or failed: a lowercase reason (no_active_device, no_push_app, no_phone_number, no_email, no_sender, push_unavailable, push_disabled, email_unavailable, not_permitted, template_channel_missing, content_purged, notify_stuck) or the channel's own error code (e.g. OPT_OUT_BLOCKED, NO_CONSENT, EMAIL_SUPPRESSED, or ENCRYPTION_KEY_MISSING when the push app has require_encryption and none of the user's devices registered a key). Null otherwise.
- Can be null
livemoderequiredboolean created_atrequiredstring - Format: date-time
has_morerequiredboolean next_cursorrequiredstring Pass it as cursor for the next page. Null on the last page.
- Can be null
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 422VALIDATION_ERROR: limit is not a positive integer.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data, error } = await honkio.notifications.list({ userId: 'user_1042', status: 'failed', limit: 20 })
if (error) throw new Error(error.message)
for (const notification of data.data) console.log(notification.id, notification.status)curl https://api.honkio.ca/v1/notifications \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/notifications/{id}Get a notification
notifications:rNode.js SDKhonkio.notifications.get()Notifications follow the key's mode: a test key sends to and reads test profiles and notifications only, through each channel's test mode.
Requires notifications:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string | The notification's id (ntf_…). |
Responses
200The notification.
Field Type Description idrequiredstring ntf_…
objectrequiredstring - One of: notification
user_idrequiredstring statusrequiredstring pending while a push is being sent; delivered once a channel took it; failed when every channel was skipped, refused or failed.
- One of: pending | delivered | failed
channelrequiredstring The channel that delivered it.
- One of: push | sms | email
- Can be null
message_idrequiredstring The SMS (/v1/messages) that delivered it.
- Can be null
email_idrequiredstring The email (/v1/emails) that delivered it.
- Can be null
push_idstring The push (/v1/push) that delivered it.
- Can be null
attempts[]requiredobject[] Each channel tried, in order.
channelrequiredstring - One of: push | sms | email
outcomerequiredstring delivered: the channel took it (a push any device accepted, an SMS the carrier took, an email the email service accepted). pending: a push or an email is being sent. skipped: the channel could not be tried (no device, phone number or email address; the channel off or not permitted to the key; no template part for it). refused: the channel refused the send, as its own endpoint would. failed: a push no device accepted, or an email refused when it was dispatched, a failed call to the email service (SES_ERROR) included (refunded); NOTIFY_STUCK when a channel had no verdict for an hour (an email still queued is left to finish; if it then fails, the channels after it are skipped notify_stuck and none is tried).
- One of: delivered | pending | skipped | refused | failed
reasonrequiredstring Why it was skipped, refused or failed: a lowercase reason (no_active_device, no_push_app, no_phone_number, no_email, no_sender, push_unavailable, push_disabled, email_unavailable, not_permitted, template_channel_missing, content_purged, notify_stuck) or the channel's own error code (e.g. OPT_OUT_BLOCKED, NO_CONSENT, EMAIL_SUPPRESSED, or ENCRYPTION_KEY_MISSING when the push app has require_encryption and none of the user's devices registered a key). Null otherwise.
- Can be null
livemoderequiredboolean created_atrequiredstring - Format: date-time
- 401Missing, invalid, revoked or expired API key.The standard error body.
- 402The account has no balance, or a LIVE key was used before the first top-up.The standard error body.
- 403The API key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
- 404NOT_FOUND: no notification with that id in the calling key's mode.The standard error body.
- 429Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).The standard error body.
- 500Unexpected server error.The standard error body.
Example
const { data: notification, error } = await honkio.notifications.get('NOTIFICATION_ID')
if (error) throw new Error(error.message)
for (const attempt of notification.attempts) console.log(attempt.channel, attempt.outcome, attempt.reason)curl https://api.honkio.ca/v1/notifications/ID \
-H "Authorization: Bearer mk_live_YOUR_KEY"
HonkIO