API reference
Verify
Phone number verification (SMS OTP) with per-verification upcharge.
/v1/verifyList verifications
verify:rNode.js SDKhonkio.verify.list()Returns a paginated list of verifications for the authenticated account, newest first.
Requires verify:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
limitquery | integer |
|
offsetquery | integer |
|
statusquery | string | Filter by status
|
Responses
200A page of verifications, newest first.
Field Type Description 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)curl https://api.honkio.ca/v1/verify \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/verifyStart a phone number verification
verify:wNode.js SDKhonkio.verify.start()Sends an OTP to the specified Canadian phone number.
Billed at your standard per-segment message rate (the OTP is one segment unless app_name is long or uses non-GSM characters; the charge is settled to the carrier's segment 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), or8ttl_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). from may be any valid NANP number in test mode, so an account with no number yet can try it; a toll-free from must still be yours and verified.
Requires verify:w.
Request body
| Field | Type | Description |
|---|---|---|
fromrequired | string | Your HonkIO number (E.164, must be active on your account). A test key may use any valid NANP number, except a toll-free one, which must be yours and verified in both modes. |
torequired | string | The phone number to verify (E.164, Canadian numbers only) |
code_length | integer | OTP digit length (default: 6)
|
ttl_minutes | integer | Minutes until the code expires (default: 10)
|
app_name | string | Brand name shown in the SMS body (default: HonkIO)
|
Responses
201Verification started: the code was sent (LIVE) or simulated (TEST, code all zeros).
Field Type Description 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. RENT_OWED: rent is owed on a number released while suspended; top up to pay it first. 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, SENDING_PAUSED, or TOLL_FREE_NOT_VERIFIED (a toll-free from number without an approved toll-free verification; test keys too). SENDING_PAUSED with details.channel "verify" means SMS-pumping detection paused live codes only: details carry paused_until, reason otp_pumping and, when one number range is paused, exchange.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_THROTTLED: the carrier asked us to slow down and did not take the code. Nothing was charged; start again after Retry-After. 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)curl -X POST https://api.honkio.ca/v1/verify \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+1416XXXXXXX",
"to": "+1613XXXXXXX"
}'/v1/verify/{id}Get a verification
verify:rNode.js SDKhonkio.verify.get()Returns a single verification record by ID.
Requires verify:r.
Parameters
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string |
Responses
200The verification.
Field Type Description 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)curl https://api.honkio.ca/v1/verify/ID \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/verify/pauseResume verification codes paused by SMS-pumping detection
verify:wLifts every pause SMS-pumping detection put on live codes (the account-wide one and each paused number range) and forgets the traffic that tripped it, so the next start goes out. Use it once you are sure the traffic is genuine, or after you have stopped the bot (a CAPTCHA or a rate limit on the form that requests codes). GET /v1/send-limit shows what is paused in verify_pause. lifted is false when nothing was paused.
Requires verify:w.
Responses
200What the lift did: lifted is false when nothing was paused.
Field Type Description liftedrequiredboolean - 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.
- 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
curl -X DELETE https://api.honkio.ca/v1/verify/pause \
-H "Authorization: Bearer mk_live_YOUR_KEY"/v1/verify/{id}/checkCheck a verification code
verify:wNode.js SDKhonkio.verify.check()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
| Parameter | Type | Description |
|---|---|---|
idrequiredpath | string |
Request body
| Field | Type | Description |
|---|---|---|
coderequired | string | 4 to 8 digit OTP code |
Responses
200Code accepted: the verification is now verified.
Field Type Description 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.
Field Type Description 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'
}curl -X POST https://api.honkio.ca/v1/verify/ID/check \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"code": "123456"
}'
HonkIO