API reference

Webhooks

Register endpoints to receive event notifications.

get/v1/webhooks

List registered webhooks

Requires webhooks:r.

Responses

  • 200Every endpoint on the account, newest first. Not paginated.
    FieldTypeDescription
    data[]requiredobject[]
    idrequiredstring
    urlrequiredstring
    eventsrequiredstring[]
    activerequiredboolean
    deactivated_reasonrequiredstring

    Why delivery disabled the endpoint, when it did: e.g. "HTTP_401 for 26h across 7 events" after 24 hours of failure across at least 5 events, or SSRF_BLOCKED.

    • Can be null
    deactivated_atrequiredstring
    • Format: date-time
    • Can be null
    failing_sincerequiredstring

    The first failed attempt since the last successful delivery; null while the endpoint is healthy. Any delivered attempt clears it.

    • Format: date-time
    • Can be null
    failed_eventsrequiredinteger

    Distinct events that have failed since failing_since. The endpoint is disabled once every attempt has failed for 24 hours and this reaches 5.

    last_success_atrequiredstring

    The last delivered attempt, to within a minute.

    • Format: date-time
    • Can be null
    last_failure_atrequiredstring
    • Format: date-time
    • Can be null
    last_failure_reasonrequiredstring

    The last failed attempt's result: HTTP_<status>, HTTP_<status>_REDIRECT_NOT_FOLLOWED, TIMEOUT or NETWORK_ERROR.

    • Can be null
    secret_rotated_atrequiredstring

    When the signing secret was last rotated (POST /v1/webhooks/{id}/rotate-secret); null while the endpoint still signs with the secret it was created with.

    • Format: date-time
    • Can be null
    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.
  • 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.webhooks.list()
if (error) throw new Error(error.message)
for (const w of data.data) console.log(w.id, w.url)
post/v1/webhooks

Register a webhook endpoint

Requires webhooks:w.

Request body

FieldTypeDescription
urlrequiredstring

HTTPS URL to deliver events to. It must answer 2xx directly: deliveries never follow a redirect, so a 3xx is recorded as a failed attempt.

  • Format: uri
  • At most 2048 characters
eventsrequiredstring[]
  • One of: message.queued | message.sending | message.sent | message.delivered | message.failed | message.undelivered | message.received | opt_out.recorded | opt_out.reinstated | account.delivery_warning | account.sending_paused | account.spend_warning | account.inbound_email_capped | account.inbound_sms_capped | email.queued | email.sent | email.delivered | email.delivery_delayed | email.bounced | email.complained | email.rejected | email.failed | email.opened | email.clicked | email.unsubscribed | email.cancelled | email.rescheduled | email.received | email_domain.verified | email_domain.verification_failed | email_domain.receiving_verified | email_domain.receiving_failed | phone_number.suspended | phone_number.released

Responses

  • 201The endpoint. signing_secret is shown only here: store it to verify X-HonkIO-Signature.
    FieldTypeDescription
    idrequiredstring
    urlrequiredstring
    eventsrequiredstring[]
    signing_secretrequiredstring

    64 hex characters.

    activerequiredboolean
    created_atrequiredstring
    • Format: date-time
    noticerequiredstring
  • 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.
  • 403LIVE_KEY_REQUIRED: test keys cannot reach live resources here. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
  • 422VALIDATION_ERROR (not a public HTTPS URL, an unknown event, or an email event while email is off) or WEBHOOK_LIMIT_REACHED (10 endpoints per account).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: webhook, error } = await honkio.webhooks.create({
  url: 'https://yourapp.ca/webhooks/honkio',
  events: ['message.delivered', 'message.failed', 'message.received'],
})
if (error) throw new Error(error.message)
console.log(webhook.signing_secret) // shown once: store it now
get/v1/webhooks/{id}

Get a webhook by ID

Requires webhooks:r.

Parameters

ParameterTypeDescription
idrequiredpathstring

Responses

  • 200The endpoint.
    FieldTypeDescription
    idrequiredstring
    urlrequiredstring
    eventsrequiredstring[]
    activerequiredboolean
    deactivated_reasonrequiredstring

    Why delivery disabled the endpoint, when it did: e.g. "HTTP_401 for 26h across 7 events" after 24 hours of failure across at least 5 events, or SSRF_BLOCKED.

    • Can be null
    deactivated_atrequiredstring
    • Format: date-time
    • Can be null
    failing_sincerequiredstring

    The first failed attempt since the last successful delivery; null while the endpoint is healthy. Any delivered attempt clears it.

    • Format: date-time
    • Can be null
    failed_eventsrequiredinteger

    Distinct events that have failed since failing_since. The endpoint is disabled once every attempt has failed for 24 hours and this reaches 5.

    last_success_atrequiredstring

    The last delivered attempt, to within a minute.

    • Format: date-time
    • Can be null
    last_failure_atrequiredstring
    • Format: date-time
    • Can be null
    last_failure_reasonrequiredstring

    The last failed attempt's result: HTTP_<status>, HTTP_<status>_REDIRECT_NOT_FOLLOWED, TIMEOUT or NETWORK_ERROR.

    • Can be null
    secret_rotated_atrequiredstring

    When the signing secret was last rotated (POST /v1/webhooks/{id}/rotate-secret); null while the endpoint still signs with the secret it was created with.

    • Format: date-time
    • Can be null
    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 such resource on this account.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.webhooks.get('WEBHOOK_ID')
if (error) throw new Error(error.message)
console.log(data.url, data.events)
patch/v1/webhooks/{id}

Update a webhook

Requires webhooks:m.

Parameters

ParameterTypeDescription
idrequiredpathstring

Request body

FieldTypeDescription
urlstring
  • Format: uri
  • At most 2048 characters
eventsstring[]
  • One of: message.queued | message.sending | message.sent | message.delivered | message.failed | message.undelivered | message.received | opt_out.recorded | opt_out.reinstated | account.delivery_warning | account.sending_paused | account.spend_warning | account.inbound_email_capped | account.inbound_sms_capped | email.queued | email.sent | email.delivered | email.delivery_delayed | email.bounced | email.complained | email.rejected | email.failed | email.opened | email.clicked | email.unsubscribed | email.cancelled | email.rescheduled | email.received | email_domain.verified | email_domain.verification_failed | email_domain.receiving_verified | email_domain.receiving_failed | phone_number.suspended | phone_number.released
activeboolean

Responses

  • 200The updated endpoint.
    FieldTypeDescription
    idrequiredstring
    urlrequiredstring
    eventsrequiredstring[]
    activerequiredboolean
  • 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.
  • 403LIVE_KEY_REQUIRED: test keys cannot reach live resources here. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
  • 404NOT_FOUND: no such resource on this account.The standard error body.
  • 422VALIDATION_ERROR: not a public HTTPS URL, an unknown event, or an email event while email is off.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 { error } = await honkio.webhooks.update('WEBHOOK_ID', { events: ['message.delivered', 'message.failed'] })
if (error) throw new Error(error.message)
delete/v1/webhooks/{id}

Delete a webhook

Requires webhooks:d.

Parameters

ParameterTypeDescription
idrequiredpathstring

Responses

  • 204Deleted, with its delivery history and dead letters.
  • 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.
  • 403LIVE_KEY_REQUIRED: test keys cannot reach live resources here. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
  • 404NOT_FOUND: no such resource on this account.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 { error } = await honkio.webhooks.remove('WEBHOOK_ID')
if (error) throw new Error(error.message)
get/v1/webhooks/{id}/deliveries

List recent delivery attempts for a webhook

Requires webhooks:r.

Parameters

ParameterTypeDescription
limitqueryinteger
  • Minimum: 1
  • Maximum: 200
  • Default: 50
idrequiredpathstring

Responses

  • 200Recent delivery attempts, newest first.
    FieldTypeDescription
    data[]requiredobject[]
    idrequiredstring
    event_idrequiredstring
    event_typerequiredstring
    attemptrequiredinteger
    successrequiredboolean
    http_statusrequiredinteger
    • Can be null
    error_reasonrequiredstring
    • Can be null
    duration_msrequiredinteger
    • Can be null
    occurred_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 such resource on this account.The standard error body.
  • 422VALIDATION_ERROR: the request failed validation; details names the fields.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.webhooks.deliveries('WEBHOOK_ID', { limit: 20 })
if (error) throw new Error(error.message)
console.log(data.data)
get/v1/webhooks/{id}/dead-letters

List events that failed all delivery attempts (dead-letter queue)

Requires webhooks:r.

Parameters

ParameterTypeDescription
limitqueryinteger
  • Minimum: 1
  • Maximum: 200
  • Default: 50
include_replayedqueryboolean
  • Default: false
idrequiredpathstring

Responses

  • 200Events that failed every attempt, newest first.
    FieldTypeDescription
    data[]requiredobject[]
    idrequiredstring
    event_idrequiredstring
    event_typerequiredstring
    failed_reasonrequiredstring

    Why the event stopped being retried: the last attempt's failure with the attempt count after about 24 hours of retries (e.g. "HTTP_500 after 8 attempts"), the same with "; endpoint disabled" when the endpoint was disabled while it was owed, ENDPOINT_DISABLED when you had switched the endpoint off, SSRF_BLOCKED, or queue_full.

    created_atrequiredstring
    • Format: date-time
    replayed_atrequiredstring
    • Format: date-time
    • Can be null
    payloadrequiredany

    The event body that failed to deliver: { id, type, created, account_id, data }.

  • 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.
  • 403LIVE_KEY_REQUIRED: test keys cannot reach live resources here. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
  • 404NOT_FOUND: no such resource on this account.The standard error body.
  • 422VALIDATION_ERROR: the request failed validation; details names the fields.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.webhooks.deadLetters('WEBHOOK_ID')
if (error) throw new Error(error.message)
for (const dl of data.data) console.log(dl.id)
post/v1/webhooks/dead-letters/{dlid}/replay

Replay a dead-lettered event against the original webhook URL

Sends the event again, signed with a fresh timestamp and marked X-HonkIO-Replay: true. 200 { status: "replayed" } when your endpoint accepted it; 502 { status: "failed", http_status, error_reason } when it did not (the event stays in the dead-letter queue and can be replayed again); 404 NOT_FOUND when the dead letter is not on your account; 409 DEAD_LETTER_ALREADY_REPLAYED when it was already replayed or a replay of it is in progress, or 409 ACCOUNT_SUSPENDED while the account is suspended or closed, in which case nothing is sent.

Requires webhooks:m.

Parameters

ParameterTypeDescription
dlidrequiredpathstring

Responses

  • 200Your endpoint accepted the replay.
    FieldTypeDescription
    statusrequiredstring
    • One of: replayed
    http_statusrequiredinteger
    • 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.
  • 403LIVE_KEY_REQUIRED: test keys cannot reach live resources here. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
  • 404NOT_FOUND: no such resource on this account.The standard error body.
  • 409DEAD_LETTER_ALREADY_REPLAYED: already replayed, or a replay is in progress. Also ACCOUNT_SUSPENDED while the account is suspended or closed. Either way, nothing was sent.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.
  • 502WEBHOOK_REPLAY_FAILED: your endpoint did not accept the replay. The event stays in the dead-letter queue.
    FieldTypeDescription
    coderequiredstring

    Machine-readable error code, e.g. VALIDATION_ERROR.

    messagerequiredstring

    Human-readable message in the request's locale (Accept-Language).

    messageEnstring

    English message, always present alongside message.

    messageFrstring

    French message, always present alongside message.

    statusCoderequiredinteger

    The HTTP status, repeated in the body.

    detailsany

    Present on some errors: an AJV validation array, or error-specific structured detail.

    statusrequiredstring
    • One of: failed
    http_statusrequiredinteger
    • Can be null
    error_reasonrequiredstring
    • Can be null

Example

const { error } = await honkio.webhooks.replay('DEAD_LETTER_ID')
if (error) throw new Error(error.message)
delete/v1/webhooks/dead-letters/{dlid}

Discard a dead-lettered event without replaying it

Requires webhooks:d.

Parameters

ParameterTypeDescription
dlidrequiredpathstring

Responses

  • 204Discarded.
  • 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.
  • 403LIVE_KEY_REQUIRED: test keys cannot reach live resources here. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
  • 404NOT_FOUND: no such resource on this account.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 { error } = await honkio.webhooks.discard('DEAD_LETTER_ID')
if (error) throw new Error(error.message)
post/v1/webhooks/{id}/reactivate

Reactivate a webhook that was auto-disabled by delivery failures

Turns delivery back on and starts the endpoint's failure streak over. Events that failed while it was off are not resent: list them with GET /v1/webhooks/{id}/dead-letters and replay each one.

Requires webhooks:m.

Parameters

ParameterTypeDescription
idrequiredpathstring

Responses

  • 200The endpoint is active again.
    FieldTypeDescription
    idrequiredstring
    activerequiredboolean
  • 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.
  • 403LIVE_KEY_REQUIRED: test keys cannot reach live resources here. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
  • 404NOT_FOUND: no such resource on this account.The standard error body.
  • 422VALIDATION_ERROR: the URL no longer resolves to a public endpoint.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 { error } = await honkio.webhooks.reactivate('WEBHOOK_ID')
if (error) throw new Error(error.message)
post/v1/webhooks/{id}/rotate-secret

Rotate a webhook's signing secret

Generates a new signing secret and returns it once. The previous secret stops signing at once. Every delivery attempt, retries included, is signed with the secret the endpoint holds at that moment, so return a non-2xx for a signature you cannot verify and the retry arrives signed with the new secret.

Requires webhooks:m.

Parameters

ParameterTypeDescription
idrequiredpathstring

Responses

  • 200The new secret, shown only here. The previous secret stops signing at once; retries of anything the endpoint rejects during the switch are re-signed with this one.
    FieldTypeDescription
    idrequiredstring
    signing_secretrequiredstring

    64 hex characters.

    secret_rotated_atrequiredstring
    • Format: date-time
    noticerequiredstring
  • 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.
  • 403LIVE_KEY_REQUIRED: test keys cannot reach live resources here. Also FORBIDDEN when the key lacks the permission this operation requires, or the account is suspended or closed.The standard error body.
  • 404NOT_FOUND: no such resource on this account.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.webhooks.rotateSecret('WEBHOOK_ID')
if (error) throw new Error(error.message)
console.log(data.signing_secret) // the old secret stopped signing: store this one