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.

post/v1/notify

Send a notification

Permissionnotifications: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

ParameterTypeDescription
Idempotency-Keyheaderstring
  • At most 255 characters

Request body

One notification to one of your users: who, in which order of channels, and what.

FieldTypeDescription
user_idrequiredstring

Your own id for the person: their recipient profile (/v1/recipients) and the user_id their push devices are registered under.

  • At least 1 characters
  • At most 255 characters
channelsstring[]

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.

  • One of: push | sms | email
textstring

The text: the SMS, the push body and the email's plain text. Up to 1600 characters. Required unless you send a template.

  • At least 1 characters
  • At most 1600 characters
titlestring

The push title. Not with a template.

  • At least 1 characters
  • At most 1000 characters
subjectstring

The email subject. Required when email may be tried and the person has an email address, unless you send a template.

  • At least 1 characters
  • At most 998 characters
htmlstring

The email's HTML body. Optional: without it the email is plain text.

templatestring

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.

  • At least 1 characters
  • At most 200 characters
variablesobject

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.

languagestring

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.

  • One of: en | fr
fromobject

The senders. 422 NOTIFY_SENDER_REQUIRED when a channel that will be tried can reach the person and has none.

smsstring

One of your numbers, E.164, to text from.

  • At least 1 characters
  • At most 32 characters
emailstring

An address on one of your verified domains. A template's default from address fills it when you leave it out.

  • At least 1 characters
  • At most 998 characters
push_app_idstring

The push app to send with. Optional when the account has exactly one.

  • At least 1 characters
  • At most 100 characters
is_commercialboolean

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.

  • Default: false

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.
    FieldTypeDescription
    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)
get/v1/notifications

List notifications

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

ParameterTypeDescription
limitquerystring

1 to 100. Default 50.

cursorquerystring

next_cursor from the previous page.

user_idquerystring

Only this user's notifications.

statusquerystring

Only notifications in this state.

  • One of: pending | delivered | failed

Responses

  • 200A page of notifications in the calling key's mode, newest first.
    FieldTypeDescription
    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)
get/v1/notifications/{id}

Get a notification

Permissionnotifications: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

ParameterTypeDescription
idrequiredpathstring

The notification's id (ntf_…).

Responses

  • 200The notification.
    FieldTypeDescription
    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)