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-auth-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: 3.2.0
info:
title: HonkIO Auth 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: Auth
description: Dashboard login and password management
paths:
/v1/auth/login:
post:
summary: Authenticate and retrieve API keys
tags:
- Auth
description: Validates email and password hash. Returns account info and API key prefix list for the dashboard session.
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- password
properties:
email:
type: string
format: email
password:
type: string
minLength: 1
security: []
responses:
'200':
description: Signed in. The two session keys are shown once; the dashboard uses them for its own calls.
content:
application/json:
schema:
description: Signed in. The two session keys are shown once; the dashboard uses them for its own calls.
type: object
additionalProperties: true
required:
- account
- api_keys
- session_key
- session_key_id
- session_test_key
- session_test_key_id
properties:
account:
type: object
additionalProperties: true
required:
- id
- name
- email
- status
- balance_cents
- created_at
properties:
id:
type: string
name:
type: string
email:
type: string
status:
type: string
enum:
- PENDING_PAYMENT
- ACTIVE
balance_cents:
type: integer
created_at:
type: string
format: date-time
api_keys:
type: array
items:
$ref: '#/components/schemas/ApiKey'
description: The account's active USER keys, without permissions or defaultDeny.
session_key:
type: string
description: A LIVE dashboard session key, valid for 7 days or until the next login or password change.
session_key_id:
type: string
session_test_key:
type: string
description: The matching TEST dashboard session key.
session_test_key_id:
type: string
'401':
description: 'INVALID_CREDENTIALS: unknown email or wrong password.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'403':
description: 'ACCOUNT_SUSPENDED: 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_LIMITED: 10 attempts per 15 minutes from one address, or 20 failures per 15 minutes for one email.'
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before retrying.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
operationId: postV1AuthLogin
x-operation-id-source: derived
/v1/auth/set-password:
post:
summary: Change account password (requires current password)
tags:
- Auth
description: 'Also signs out every dashboard session and disconnects every app connected through OAuth: each connection''s API key and tokens are revoked.'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
- new_password
- current_password
properties:
email:
type: string
format: email
new_password:
type: string
minLength: 10
current_password:
type: string
minLength: 1
security: []
responses:
'200':
description: Password changed. Every dashboard session is signed out.
content:
application/json:
schema:
description: Password changed. Every dashboard session is signed out.
type: object
additionalProperties: true
required:
- status
properties:
status:
type: string
enum:
- password_set
'401':
description: 'UNAUTHORIZED or INVALID_CREDENTIALS: unknown account or wrong current password.'
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_LIMITED: 10 attempts per hour from one address.'
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before retrying.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
operationId: postV1AuthSetPassword
x-operation-id-source: derived
/v1/auth/forgot-password:
post:
summary: Request a password reset email
tags:
- Auth
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
properties:
email:
type: string
format: email
security: []
responses:
'200':
description: Always answered, whether or not the email has an account, so the response reveals nothing.
content:
application/json:
schema:
description: Always answered, whether or not the email has an account, so the response reveals nothing.
type: object
additionalProperties: true
required:
- status
properties:
status:
type: string
enum:
- reset_email_sent
'422':
description: 'VALIDATION_ERROR: the request failed validation; details names the fields.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'RATE_LIMITED: 5 requests per 15 minutes from one address.'
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before retrying.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
operationId: postV1AuthForgotPassword
x-operation-id-source: derived
/v1/auth/reset-password:
post:
summary: Reset password using emailed token
tags:
- Auth
description: 'Also signs out every dashboard session and disconnects every app connected through OAuth: each connection''s API key and tokens are revoked.'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- token
- new_password
properties:
token:
type: string
minLength: 64
maxLength: 64
description: Reset token from email link
new_password:
type: string
minLength: 10
security: []
responses:
'200':
description: Password reset. Every dashboard session is signed out.
content:
application/json:
schema:
description: Password reset. Every dashboard session is signed out.
type: object
additionalProperties: true
required:
- status
properties:
status:
type: string
enum:
- password_reset
'422':
description: 'VALIDATION_ERROR: details.token when the token is unknown, used or expired.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'RATE_LIMITED: 10 attempts per 15 minutes from one address.'
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before retrying.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
operationId: postV1AuthResetPassword
x-operation-id-source: derived
/v1/auth/step-up:
post:
summary: Issue a short-lived elevated-permission token after password re-entry
tags:
- Auth
description: 'Send the returned token as X-Step-Up-Token on the one request it is for: it is honoured once, expires after 5 minutes, and only works with the API key that requested it. `compliance:d` allows a right-to-erasure call. `api_keys:elevate` allows creating or rotating a key with permissions beyond the calling key''s.'
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- password
- scope
properties:
password:
type: string
minLength: 1
scope:
type: string
enum:
- compliance:d
- api_keys:elevate
security:
- apiKey: []
- apiKeyHeader: []
responses:
'200':
description: A single-use token for the X-Step-Up-Token header, valid for 5 minutes with the key that requested it.
content:
application/json:
schema:
description: A single-use token for the X-Step-Up-Token header, valid for 5 minutes with the key that requested it.
type: object
additionalProperties: true
required:
- token
- scope
- expires_at
properties:
token:
type: string
scope:
type: string
enum:
- compliance:d
- api_keys:elevate
expires_at:
type: string
format: date-time
'401':
description: 'UNAUTHORIZED: missing or invalid API key, or the password is wrong.'
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_LIMITED: 10 attempts per 15 minutes from one address, 20 wrong passwords per 15 minutes for one account, or the account-wide 100 requests per second.'
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before retrying.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'500':
description: Unexpected server error.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
operationId: postV1AuthStepUp
x-operation-id-source: derived
/v1/auth/verify-email:
post:
summary: Confirm an account email address using the link emailed at signup
tags:
- Auth
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- token
properties:
token:
type: string
minLength: 64
maxLength: 64
description: Email verification token
security: []
responses:
'200':
description: Email address confirmed.
content:
application/json:
schema:
description: Email address confirmed.
type: object
additionalProperties: true
required:
- status
properties:
status:
type: string
enum:
- email_verified
'422':
description: 'VALIDATION_ERROR: details.token says whether the token is invalid, expired or already used.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'RATE_LIMITED: 20 attempts per hour from one address.'
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before retrying.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
operationId: postV1AuthVerifyEmail
x-operation-id-source: derived
/v1/auth/resend-verification:
post:
summary: Send a fresh email-verification link to an account email
tags:
- Auth
requestBody:
required: true
content:
application/json:
schema:
type: object
required:
- email
properties:
email:
type: string
format: email
security: []
responses:
'200':
description: Always answered, whether or not the email has an unverified account, so the response reveals nothing.
content:
application/json:
schema:
description: Always answered, whether or not the email has an unverified account, so the response reveals nothing.
type: object
additionalProperties: true
required:
- status
properties:
status:
type: string
enum:
- verification_email_sent
'422':
description: 'VALIDATION_ERROR: the request failed validation; details names the fields.'
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
'429':
description: 'RATE_LIMITED: 5 requests per hour from one address.'
headers:
Retry-After:
schema:
type: integer
description: Seconds to wait before retrying.
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
operationId: postV1AuthResendVerification
x-operation-id-source: derived
components:
schemas:
ApiKeyPermissions:
type: object
description: 'Per-resource permissions. Each key is a resource name; value is a string of allowed operation letters: r=read, w=write/create, m=modify/update, d=delete. A missing key denies all access to that resource.'
additionalProperties:
type: string
example:
messages: rw
contacts: r
phone_numbers: r
ApiKey:
type: object
additionalProperties: true
required:
- id
- keyPrefix
- mode
- label
- createdAt
- lastUsedAt
properties:
id:
type: string
keyPrefix:
type: string
description: Non-secret prefix for display and identification.
mode:
type: string
enum:
- LIVE
- TEST
label:
type:
- string
- 'null'
createdAt:
type: string
format: date-time
lastUsedAt:
type:
- string
- 'null'
format: date-time
defaultDeny:
type: boolean
description: Present on GET /v1/accounts/me and /v1/accounts/{id}; absent from the login response.
permissions:
$ref: '#/components/schemas/ApiKeyPermissions'
email_domain_ids:
type:
- array
- 'null'
items:
type: string
description: 'The email domains this key may send from (ids from /v1/email-domains): null when unrestricted, [] when restricted to none (its domains were deleted). Present on GET /v1/accounts/me and /v1/accounts/{id}; absent from the login response.'
oauth_grant:
type: boolean
description: 'True when an OAuth connection holds this key: it can be revoked but not rotated (409 CONFLICT, details.reason "oauth_grant"). Present on GET /v1/accounts/me and /v1/accounts/{id}; absent from the login response.'
description: An active (unrevoked) API key, never the key itself. Field names are camelCase here, unlike the rest of the API.
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.'