honkio-ca Verify API

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

Operations 4

GET /v1/verify List verifications #
POST /v1/verify Start a phone number verification #
GET /v1/verify/{id} Get a verification #
POST /v1/verify/{id}/check Check a verification code #

Work with this as data

Every API here is available over the APIs.io API and to AI agents over MCP.

MCP server

One button, every client — Claude, Cursor, VS Code and the rest.

https://apis.io/mcp

Tools for apis

7 MCP tools reach this
  • find_apisBrowse and filter every API in the catalog.
  • get_api_artifactsOne API's artifacts, grouped by type.
  • get_openapiThe primary OpenAPI for this API.
  • find_similar_apisAPIs that look like this one.
  • apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
  • resolveTurn a domain, URL or GitHub org into the provider it belongs to.
  • find_cohortsEvery scored population of providers in the catalog.
All 92 tools →

Call it yourself

curl for this page
This API
curl "https://apis.io/api/v1/apis/honkio-ca:honkio-ca-verify-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"

Discovery needs no key. Ratings and market analysis are Pro.

Get an API key

Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.

A second provider on the same verified email joins the account you already have.

OpenAPI Specification

honkio-ca-verify-api-openapi.yml Raw ↑
openapi: 3.2.0
info:
  title: HonkIO Verify API
  description: 'Canadian-focused SMS gateway API.


    ## Canadian Compliance

    - **CASL**: All commercial messages require consent. Use `/v1/compliance/consents` to record.

    - **DNCL**: CRTC Do Not Call List checking is coming soon (not yet enforced).

    - **PIPEDA / Quebec Law 25**: Data is stored in Canada (ca-central-1). Requests are processed in the United States in transit. Right-to-erasure available.


    ## Authentication

    Provide your API key via `Authorization: Bearer mk_live_...` or `X-API-Key: mk_live_...`.

    Test keys never send, never charge and can''t change live data; they work before your first top-up.


    ## Rate limits

    100 requests per second per account. Every authenticated response carries `X-RateLimit-Limit`, `X-RateLimit-Remaining` and `X-RateLimit-Reset`.


    ## Pagination

    Shape follows the route family, not one convention across the API: documented here rather than changed. Messages listings return `{ data, meta: { page, limit, total, pages } }`. Contacts, Contact Groups, Lists and Verify listings return `{ data, total, limit, offset }`. Compliance consent and opt-out listings accept `page`/`limit` and return `{ data }`, with no total. Account transactions use a cursor: pass `before`, get back `has_more`.'
  version: 1.0.0
  contact:
    name: HonkIO Support
    email: support@honkio.ca
servers:
- url: https://api.honkio.ca
  description: Production
- url: http://localhost:3000
  description: Local development
security:
- apiKey: []
- apiKeyHeader: []
tags:
- name: Verify
  description: Phone number verification (SMS OTP) with per-verification upcharge
paths:
  /v1/verify:
    get:
      summary: List verifications
      tags:
      - Verify
      description: 'Returns a paginated list of verifications for the authenticated account, newest first.


        Requires `verify:r`.'
      parameters:
      - schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 50
        in: query
        name: limit
        required: false
      - schema:
          type: integer
          minimum: 0
          default: 0
        in: query
        name: offset
        required: false
      - schema:
          type: string
          enum:
          - pending
          - verified
          - expired
          - max_attempts
        in: query
        name: status
        required: false
        description: Filter by status
      security:
      - apiKey: []
      - apiKeyHeader: []
      x-honkio-permission: verify:r
      responses:
        '200':
          description: A page of verifications, newest first.
          content:
            application/json:
              schema:
                description: A page of verifications, newest first.
                allOf:
                - $ref: '#/components/schemas/PaginationOffset'
                - type: object
                  additionalProperties: true
                  required:
                  - data
                  properties:
                    data:
                      type: array
                      items:
                        $ref: '#/components/schemas/Verification'
        '401':
          description: Missing, invalid, revoked or expired API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: The account has no balance, or a LIVE key was used before the first top-up.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the permission this operation requires, or the account is suspended or closed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: 'VALIDATION_ERROR: the request failed validation; details names the fields.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      operationId: getV1Verify
      x-operation-id-source: derived
    post:
      summary: Start a phone number verification
      tags:
      - Verify
      description: '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). `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`.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - from
              - to
              properties:
                from:
                  type: string
                  description: 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.
                to:
                  type: string
                  description: The phone number to verify (E.164, Canadian numbers only)
                code_length:
                  type: integer
                  enum:
                  - 4
                  - 6
                  - 8
                  description: 'OTP digit length (default: 6)'
                ttl_minutes:
                  type: integer
                  minimum: 1
                  maximum: 60
                  description: 'Minutes until the code expires (default: 10)'
                app_name:
                  type: string
                  maxLength: 64
                  description: 'Brand name shown in the SMS body (default: HonkIO)'
      security:
      - apiKey: []
      - apiKeyHeader: []
      x-honkio-permission: verify:w
      responses:
        '201':
          description: 'Verification started: the code was sent (LIVE) or simulated (TEST, code all zeros).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Verification'
        '401':
          description: Missing, invalid, revoked or expired API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: 'INSUFFICIENT_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.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: ACCOUNT_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).
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: VALIDATION_ERROR, NON_CANADIAN_NUMBER, RESERVED_DESTINATION, UNDELIVERABLE_NUMBER, NOT_A_MOBILE_NUMBER or LINK_SHORTENER_BLOCKED. A refused start costs nothing.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: RATE_LIMITED (one start per recipient per 60 seconds, Retry-After 60), DAILY_LIMIT_REACHED, FANOUT_LIMIT_REACHED, NUMBER_RATE_LIMITED or RECIPIENT_RATE_LIMITED.
          headers:
            Retry-After:
              schema:
                type: integer
              description: Seconds to wait before retrying.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '451':
          description: 'OPT_OUT_BLOCKED: the recipient opted out.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '502':
          description: 'CARRIER_ERROR: the carrier refused the SMS. The charge is refunded.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '503':
          description: 'CARRIER_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.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      operationId: postV1Verify
      x-operation-id-source: derived
  /v1/verify/{id}:
    get:
      summary: Get a verification
      tags:
      - Verify
      description: 'Returns a single verification record by ID.


        Requires `verify:r`.'
      parameters:
      - schema:
          type: string
        in: path
        name: id
        required: true
      security:
      - apiKey: []
      - apiKeyHeader: []
      x-honkio-permission: verify:r
      responses:
        '200':
          description: The verification.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Verification'
        '401':
          description: Missing, invalid, revoked or expired API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: The account has no balance, or a LIVE key was used before the first top-up.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the permission this operation requires, or the account is suspended or closed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: VERIFICATION_NOT_FOUND. A test key finds TEST verifications only.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          description: 'Rate limit reached: 100 requests per second per account, or a route-specific limit (Retry-After set where one applies).'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Unexpected server error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      operationId: getV1VerifyById
      x-operation-id-source: derived
  /v1/verify/{id}/check:
    post:
      summary: Check a verification code
      tags:
      - Verify
      description: '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`.'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - code
              properties:
                code:
                  type: string
                  description: 4 to 8 digit OTP code
      parameters:
      - schema:
          type: string
        in: path
        name: id
        required: true
      security:
      - apiKey: []
      - apiKeyHeader: []
      x-honkio-permission: verify:w
      responses:
        '200':
          description: 'Code accepted: the verification is now verified.'
          content:
            application/json:
              schema:
                description: 'Code accepted: the verification is now verified.'
                allOf:
                - $ref: '#/components/schemas/Verification'
                - type: object
                  additionalProperties: true
                  required:
                  - attempts_remaining
                  properties:
                    attempts_remaining:
                      type: integer
                      description: Always 0 on success.
        '401':
          description: Missing, invalid, revoked or expired API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '402':
          description: The account has no balance, or a LIVE key was used before the first top-up.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '403':
          description: The API key lacks the permission this operation requires, or the account is suspended or closed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '404':
          description: VERIFICATION_NOT_FOUND. A test key finds TEST verifications only.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '409':
          description: VERIFICATION_ALREADY_VERIFIED.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '410':
          description: 'VERIFICATION_EXPIRED: start a new verification.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '422':
          description: VALIDATION_ERROR (not 4 to 8 digits) or VERIFICATION_INVALID_CODE, which carries attempts_remaining.
          content:
            application/json:
              schema:
                description: VALIDATION_ERROR (not 4 to 8 digits) or VERIFICATION_INVALID_CODE, which carries attempts_remaining.
                allOf:
                - $ref: '#/components/schemas/Error'
                - type: object
                  additionalProperties: true
                  properties:
                    attempts_remaining:
                      type: integer
                      description: Wrong-code attempts left. Present only on VERIFICATION_INVALID_CODE.
        '429':
          description: 'VERIFICATION_MAX_ATTEMPTS: five wrong codes; start a new verification. Also RATE_LIMITED at 100 requests per second.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: 'INTERNAL_ERROR: unexpected server error.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
      operationId: postV1VerifyByIdCheck
      x-operation-id-source: derived
components:
  schemas:
    PaginationOffset:
      type: object
      additionalProperties: true
      required:
      - total
      - limit
      - offset
      properties:
        total:
          type: integer
          description: Total matching records.
        limit:
          type: integer
        offset:
          type: integer
      description: Offset pagination, returned alongside `data` by the verify, contacts, contact groups and lists listings.
    Verification:
      type: object
      additionalProperties: true
      required:
      - id
      - phone_number
      - from_number
      - status
      - attempts
      - code_length
      - app_name
      - mode
      - cost_cents
      - expires_at
      - verified_at
      - created_at
      properties:
        id:
          type: string
        phone_number:
          type: string
        from_number:
          type: string
        status:
          type: string
          enum:
          - pending
          - verified
          - expired
          - max_attempts
        attempts:
          type: integer
        code_length:
          type: integer
        app_name:
          type:
          - string
          - 'null'
        mode:
          type: string
          enum:
          - LIVE
          - TEST
          description: 'TEST verifications are simulated: no SMS is sent, nothing is billed, and the code is always 000000 padded to code_length.'
        cost_cents:
          type: integer
          description: 'Cost in cents CAD. On a TEST verification this is 0: nothing was charged.'
        expires_at:
          type: string
          format: date-time
        verified_at:
          type:
          - string
          - 'null'
          format: date-time
        created_at:
          type: string
          format: date-time
      description: A phone-number verification (SMS OTP). status is lowercase, unlike message statuses.
    Error:
      type: object
      description: Standard error body. The one visible exception is the OAuth 2.1 surface (/oauth/token, /oauth/register, /oauth/revoke), which follows RFC 6749/7591/7009 and answers { error, error_description } instead.
      required:
      - code
      - message
      - statusCode
      properties:
        code:
          type: string
          description: Machine-readable error code, e.g. VALIDATION_ERROR.
        message:
          type: string
          description: Human-readable message in the request's locale (Accept-Language).
        messageEn:
          type: string
          description: English message, always present alongside message.
        messageFr:
          type: string
          description: French message, always present alongside message.
        statusCode:
          type: integer
          description: The HTTP status, repeated in the body.
        details:
          description: 'Present on some errors: an AJV validation array, or error-specific structured detail.'
  securitySchemes:
    apiKey:
      type: http
      scheme: bearer
      bearerFormat: API Key
      description: Use `mk_live_...` for production or `mk_test_...` for testing.
    apiKeyHeader:
      type: apiKey
      in: header
      name: X-API-Key
      description: 'Alternative to the Authorization header: send `mk_live_...` or `mk_test_...` as X-API-Key directly.'