API reference

Verify

Phone number verification (SMS OTP) with per-verification upcharge.

get/v1/verify

List verifications

Returns a paginated list of verifications for the authenticated account, newest first.

Requires verify:r.

Parameters

ParameterTypeDescription
limitqueryinteger
  • Minimum: 1
  • Maximum: 100
  • Default: 50
offsetqueryinteger
  • Minimum: 0
  • Default: 0
statusquerystring

Filter by status

  • One of: pending | verified | expired | max_attempts

Responses

  • 200A page of verifications, newest first.
    FieldTypeDescription
    totalrequiredinteger

    Total matching records.

    limitrequiredinteger
    offsetrequiredinteger
    data[]requiredobject[]
    idrequiredstring
    phone_numberrequiredstring
    from_numberrequiredstring
    statusrequiredstring
    • One of: pending | verified | expired | max_attempts
    attemptsrequiredinteger
    code_lengthrequiredinteger
    app_namerequiredstring
    • Can be null
    moderequiredstring

    TEST verifications are simulated: no SMS is sent, nothing is billed, and the code is always 000000 padded to code_length.

    • One of: LIVE | TEST
    cost_centsrequiredinteger

    Cost in cents CAD. On a TEST verification this is 0: nothing was charged.

    expires_atrequiredstring
    • Format: date-time
    verified_atrequiredstring
    • 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.
  • 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.verify.list({ status: 'pending', limit: 20 })
if (error) throw new Error(error.message)
console.log(data.total)
post/v1/verify

Start a phone number verification

Sends an OTP to the specified Canadian phone number.

Billed at your standard per-part message rate (the OTP is one part unless app_name is long or uses non-GSM characters; the charge is settled to the carrier's part count) plus a per-verification upcharge: see verification_upcharge_cents from GET /v1/pricing. A verification the carrier rejects is refunded in full.

Options:

  • code_length: digits in the OTP, 4, 6 (default), or 8
  • ttl_minutes: how long the code is valid (1 to 60 min, default 10)
  • app_name: brand name shown in the SMS, e.g. "Acme" → "Your Acme verification code is: …"

In test mode (mk_test_... key) no SMS is sent; the code is always all zeros for the chosen length (e.g. 000000 for 6-digit, 0000 for 4-digit).

Requires verify:w.

Request body

FieldTypeDescription
fromrequiredstring

Your HonkIO number (E.164, must be active on your account)

torequiredstring

The phone number to verify (E.164, Canadian numbers only)

code_lengthinteger

OTP digit length (default: 6)

  • One of: 4 | 6 | 8
ttl_minutesinteger

Minutes until the code expires (default: 10)

  • Minimum: 1
  • Maximum: 60
app_namestring

Brand name shown in the SMS body (default: HonkIO)

  • At most 64 characters

Responses

  • 201Verification started: the code was sent (LIVE) or simulated (TEST, code all zeros).
    FieldTypeDescription
    idrequiredstring
    phone_numberrequiredstring
    from_numberrequiredstring
    statusrequiredstring
    • One of: pending | verified | expired | max_attempts
    attemptsrequiredinteger
    code_lengthrequiredinteger
    app_namerequiredstring
    • Can be null
    moderequiredstring

    TEST verifications are simulated: no SMS is sent, nothing is billed, and the code is always 000000 padded to code_length.

    • One of: LIVE | TEST
    cost_centsrequiredinteger

    Cost in cents CAD. On a TEST verification this is 0: nothing was charged.

    expires_atrequiredstring
    • Format: date-time
    verified_atrequiredstring
    • Format: date-time
    • Can be null
    created_atrequiredstring
    • Format: date-time
  • 401Missing, invalid, revoked or expired API key.The standard error body.
  • 402INSUFFICIENT_BALANCE: the balance cannot cover the send. Also PAYMENT_REQUIRED when a LIVE key is used before the first top-up.The standard error body.
  • 403ACCOUNT_NOT_VERIFIED, PHONE_NUMBER_NOT_OWNED, ALLOW_LIST_BLOCKED, DENY_LIST_BLOCKED or SENDING_PAUSED.The standard error body.
  • 422VALIDATION_ERROR, NON_CANADIAN_NUMBER, RESERVED_DESTINATION, UNDELIVERABLE_NUMBER, NOT_A_MOBILE_NUMBER or LINK_SHORTENER_BLOCKED. A refused start costs nothing.The standard error body.
  • 429RATE_LIMITED (one start per recipient per 60 seconds, Retry-After 60), DAILY_LIMIT_REACHED, FANOUT_LIMIT_REACHED, NUMBER_RATE_LIMITED or RECIPIENT_RATE_LIMITED.The standard error body.
  • 451OPT_OUT_BLOCKED: the recipient opted out.The standard error body.
  • 500Unexpected server error.The standard error body.
  • 502CARRIER_ERROR: the carrier refused the SMS. The charge is refunded.The standard error body.
  • 503CARRIER_UNAVAILABLE: the carrier could not be reached. Nothing was sent or charged; retry shortly. CARRIER_TIMEOUT: the carrier did not answer in time, so the code may or may not have reached the recipient. The verification is closed, so that code can never be checked, and the charge is refunded: start a new one.The standard error body.

Example

const { data: verification, error } = await honkio.verify.start({
  from: '+1416XXXXXXX', // one of your HonkIO numbers
  to: '+1613XXXXXXX',
  appName: 'Acme',
})
if (error) throw new Error(error.message)
console.log(verification.id)
get/v1/verify/{id}

Get a verification

Returns a single verification record by ID.

Requires verify:r.

Parameters

ParameterTypeDescription
idrequiredpathstring

Responses

  • 200The verification.
    FieldTypeDescription
    idrequiredstring
    phone_numberrequiredstring
    from_numberrequiredstring
    statusrequiredstring
    • One of: pending | verified | expired | max_attempts
    attemptsrequiredinteger
    code_lengthrequiredinteger
    app_namerequiredstring
    • Can be null
    moderequiredstring

    TEST verifications are simulated: no SMS is sent, nothing is billed, and the code is always 000000 padded to code_length.

    • One of: LIVE | TEST
    cost_centsrequiredinteger

    Cost in cents CAD. On a TEST verification this is 0: nothing was charged.

    expires_atrequiredstring
    • Format: date-time
    verified_atrequiredstring
    • 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.
  • 404VERIFICATION_NOT_FOUND. A test key finds TEST verifications only.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.verify.get('VERIFICATION_ID')
if (error) throw new Error(error.message)
console.log(data.status, data.attempts_remaining)
post/v1/verify/{id}/check

Check a verification code

Submit the OTP code the end-user received. Max 5 attempts. Accepts 4, 6, or 8 digit codes depending on how the verification was started.

Requires verify:w.

Parameters

ParameterTypeDescription
idrequiredpathstring

Request body

FieldTypeDescription
coderequiredstring

4 to 8 digit OTP code

Responses

  • 200Code accepted: the verification is now verified.
    FieldTypeDescription
    idrequiredstring
    phone_numberrequiredstring
    from_numberrequiredstring
    statusrequiredstring
    • One of: pending | verified | expired | max_attempts
    attemptsrequiredinteger
    code_lengthrequiredinteger
    app_namerequiredstring
    • Can be null
    moderequiredstring

    TEST verifications are simulated: no SMS is sent, nothing is billed, and the code is always 000000 padded to code_length.

    • One of: LIVE | TEST
    cost_centsrequiredinteger

    Cost in cents CAD. On a TEST verification this is 0: nothing was charged.

    expires_atrequiredstring
    • Format: date-time
    verified_atrequiredstring
    • Format: date-time
    • Can be null
    created_atrequiredstring
    • Format: date-time
    attempts_remainingrequiredinteger

    Always 0 on success.

  • 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.
  • 404VERIFICATION_NOT_FOUND. A test key finds TEST verifications only.The standard error body.
  • 409VERIFICATION_ALREADY_VERIFIED.The standard error body.
  • 410VERIFICATION_EXPIRED: start a new verification.The standard error body.
  • 422VALIDATION_ERROR (not 4 to 8 digits) or VERIFICATION_INVALID_CODE, which carries attempts_remaining.
    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.

    attempts_remaininginteger

    Wrong-code attempts left. Present only on VERIFICATION_INVALID_CODE.

  • 429VERIFICATION_MAX_ATTEMPTS: five wrong codes; start a new verification. Also RATE_LIMITED at 100 requests per second.The standard error body.
  • 500INTERNAL_ERROR: unexpected server error.The standard error body.

Example

const { data, error } = await honkio.verify.check('VERIFICATION_ID', { code: '123456' })
if (error?.name === 'VERIFICATION_INVALID_CODE') {
  console.log(error.details) // { attempts_remaining: 4 }
} else if (data) {
  console.log(data.status) // 'verified'
}