Documentation
Endpoints
Four calls — ping, send, check, cancel — plus the read that tells you what happened to a code nobody received.
Everything lives under https://api.callable.com.au, authenticated with a bearer key, and anything with a body is application/json.
GET /v1/ping
Confirms a key works and reports what it can reach. Free, no side effects.
curl https://api.callable.com.au/v1/ping \
-H "Authorization: Bearer $CALLABLE_API_KEY"
POST /v1/otp/send
Generates a code, delivers it, and returns the pending verification.
| Field | Type | Default | Notes |
|---|---|---|---|
phone | string | required | E.164, or a national number plus country |
country | string | your workspace's number | AU, US, CA, GB, NZ. Ignored when phone is E.164 |
channel | voice | sms | voice | |
brand_name | string | your workspace name | Spoken and written in the message. ≤ 60 chars |
code_length | integer | 6 | 4–8 |
ttl_seconds | integer | 300 | 60–900 |
max_attempts | integer | 5 | 1–10 |
metadata | object | {} | Opaque JSON, echoed back on every read. Put your own user id here |
curl -X POST https://api.callable.com.au/v1/otp/send \
-H "Authorization: Bearer $CALLABLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"phone": "+61412345678",
"channel": "sms",
"metadata": { "user_id": "u_123" }
}'
201 Created:
{
"id": "3f2a8c14-…",
"status": "pending",
"channel": "sms",
"phone": "+61412345678",
"attempts": 0,
"max_attempts": 5,
"expires_at": "2026-08-14T04:05:00+00:00",
"verified_at": null,
"created_at": "2026-08-14T04:00:00+00:00",
"delivery": {
"ok": true,
"channel": "sms",
"provider_id": "3d38c43b-…",
"from_number": "+61400111222",
"error_code": null,
"error_message": null
},
"metadata": { "user_id": "u_123" }
}
The code itself is never in any response.
delivery carries diagnostics for when a user says the code never arrived — whether we handed it over, which number it came from, and the failure reason if there was one. Its inner fields are informational and may change; do not build logic on them.
Resending supersedes. Requesting a code for a number that already has a pending one kills the old code immediately. That is what makes "resend" unambiguous — but it means an old id is dead once you resend, so store the new one.
POST /v1/otp/check
Compares what your user typed against a pending verification.
| Field | Type | Notes |
|---|---|---|
code | string | required. Non-digits are stripped, so a pasted 123 456 is not counted as a wrong guess |
verification_id | string | The id from send. Preferred |
phone | string | Alternative to verification_id — checks the newest pending code for that number |
country | string | Country to assume for a national-format phone |
Provide one of verification_id or phone.
curl -X POST https://api.callable.com.au/v1/otp/check \
-H "Authorization: Bearer $CALLABLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "verification_id": "3f2a8c14-…", "code": "123456" }'
Correct code — 200:
{ "id": "3f2a8c14-…", "status": "verified", "verified": true, "verified_at": "2026-08-14T04:01:12+00:00" }
Wrong code — also 200:
{ "id": "3f2a8c14-…", "status": "pending", "verified": false, "attempts": 1, "attempts_remaining": 4 }
A wrong code is not an error — branch on verified, not on the status code.
Checking again after a success is safe. It returns the same success without spending an attempt, so a double-submitted form or a retried webhook does not lock your user out.
GET /v1/otp/{id}
Current state of one verification. Useful when a user reports the code never arrived — delivery carries the reason.
curl https://api.callable.com.au/v1/otp/3f2a8c14-… \
-H "Authorization: Bearer $CALLABLE_API_KEY"
POST /v1/otp/{id}/cancel
Abandons a pending verification — for instance when your user corrects their number. Idempotent: cancelling a finished verification returns it unchanged.
curl -X POST https://api.callable.com.au/v1/otp/3f2a8c14-…/cancel \
-H "Authorization: Bearer $CALLABLE_API_KEY"
Verification statuses
| Status | Meaning |
|---|---|
pending | Delivered, waiting for a code. The only status that accepts one |
verified | The correct code was submitted |
expired | The time limit elapsed |
failed | The attempt budget was spent |
undelivered | Delivery never succeeded |
canceled | Superseded by a newer code, or cancelled |
Everything except pending is terminal.