Getting started
Send your first Canadian SMS in under 5 minutes.
Quickstart
- Create a free account — get live and test API keys instantly.
- Record CASL consent for each phone number you'll message.
- Optionally provision a Canadian long code number to send from.
- Send your first message using the REST API.
Authentication
All API requests require a Bearer token in the Authorization header. Use test keys (mk_test_...) for development — no real SMS are sent, no charges. Use live keys (mk_live_...) for production.
Phone Numbers
Search for available Canadian numbers, provision one, and use it as the from field when sending.
curl https://api.honkio.ca/v1/phone-numbers/search?area_codes=416 \
-H "Authorization: Bearer mk_live_YOUR_KEY"
# Provision a number
curl -X POST https://api.honkio.ca/v1/phone-numbers \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"phone_number": "+14165550100"}'CASL Consent (required before sending)
Under CASL, you must record consent before sending a commercial message to any recipient. The API will block sends to phone numbers without valid consent (HTTP 451).
curl -X POST https://api.honkio.ca/v1/compliance/consents \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone_number": "+16135550199",
"consent_type": "express",
"source_description": "Website opt-in form",
"source_ip": "203.0.113.1"
}'Express consent never expires. Implied consent expires after 2 years per CASL §10(9).
Sending SMS
Send a message using a provisioned number. The API validates the Canadian destination number, checks CASL consent, and checks the DNCL before delivery.
curl -X POST https://api.honkio.ca/v1/messages \
-H "Authorization: Bearer mk_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "+14165550100",
"to": "+16135550199",
"body": "Hello from HonkIO! 🇨🇦"
}'Phone Number Verification (OTP)
Use the Verify API to confirm ownership of a phone number before sending commercial messages. Your end-user receives a one-time code via SMS; submit it to the check endpoint to confirm.
# Start a verification (sends OTP SMS)
curl -X POST https://api.honkio.ca/v1/verify -H "Authorization: Bearer mk_live_YOUR_KEY" -H "Content-Type: application/json" -d '{
"from": "+14165550100",
"to": "+16135550199",
"code_length": 6,
"ttl_minutes": 10,
"app_name": "Acme"
}'
# Response: { "id": "clxxx...", "status": "pending", "code_length": 6, ... }
# Check the code submitted by your user
curl -X POST https://api.honkio.ca/v1/verify/clxxx.../check -H "Authorization: Bearer mk_live_YOUR_KEY" -H "Content-Type: application/json" -d '{ "code": "483721" }'
# Response 200: { "status": "verified", ... }
# Response 422: { "code": "VERIFICATION_INVALID_CODE", "attempts_remaining": 4 }
# Fetch status at any time
curl https://api.honkio.ca/v1/verify/clxxx... -H "Authorization: Bearer mk_live_YOUR_KEY"In test mode the code is always all zeros for the chosen length (e.g. 000000 for 6-digit). No SMS is sent.
Webhooks
Register a webhook endpoint to receive delivery receipts and inbound messages. Every payload is signed with HMAC-SHA256 — verify the X-HonkIO-Signature header.
{
"id": "evt_01HXYZ...",
"type": "message.delivered",
"created": "2024-01-15T12:00:00Z",
"account_id": "acc_01HXYZ...",
"data": {
"message_id": "msg_01HXYZ...",
"to": "+16135550199",
"status": "delivered"
}
}
// Headers: X-HonkIO-Signature, X-HonkIO-Timestamp, X-HonkIO-EventError codes
| HTTP | Code | Meaning |
|---|---|---|
| 401 | UNAUTHORIZED | Missing or invalid API key |
| 402 | INSUFFICIENT_BALANCE | Account balance too low |
| 404 | VERIFICATION_NOT_FOUND | Verification ID not found or not owned by this account |
| 409 | VERIFICATION_ALREADY_VERIFIED | This number has already been verified |
| 410 | VERIFICATION_EXPIRED | The verification code has expired |
| 422 | NON_CANADIAN_NUMBER | Not a valid Canadian E.164 number |
| 422 | VERIFICATION_INVALID_CODE | Incorrect code — attempts_remaining shows how many tries are left |
| 422 | ALLOW_LIST_BLOCKED | Recipient is not on the API key's ALLOW list |
| 422 | DENY_LIST_BLOCKED | Recipient is on the API key's DENY list |
| 429 | RATE_LIMITED | Too many requests — slow down |
| 429 | VERIFICATION_MAX_ATTEMPTS | Too many wrong attempts — this verification is locked |
| 451 | OPT_OUT_BLOCKED | Recipient has opted out — legally blocked |
| 451 | NO_CONSENT | No valid CASL consent on file |
| 451 | CONSENT_EXPIRED | Implied consent expired (2-year CASL limit) |
| 451 | DNCL_BLOCKED | Number on CRTC DNCL — no exemption applies |
Honk.IO