API docs.
Send SMS and one-time codes to every Ghanaian network with one HTTP call. JSON in, JSON out, and the sandbox is free.
Introduction
Every request goes to this base URL:
Send JSON with Content-Type: application/json. Responses are JSON too. Successful
calls return 200 or 202; anything else returns an
error with a message you can show to a person.
Authentication
Put your API key in the X-API-Key header on every request. You'll find your keys in the
dashboard under API keys. Keys are shown once when they're made, so copy them somewhere safe.
| Key | Starts with | What it does |
|---|---|---|
| Live | nk_live_ | Sends real messages and uses your credit. |
| Sandbox | nk_test_ | Same requests and responses. Nothing is sent and nothing is charged. |
Sandbox
Build your whole integration with a nk_test_ key before you spend anything.
- Messages are accepted, logged and marked
delivered, but never reach a phone. - No credit is used and no sender ID approval is needed.
- Send a code returns the code in the response, so you can test the whole one-time-code flow without a phone.
When it works, swap in your live key. Nothing else changes.
Phone numbers
Send Ghana numbers in any common format. We clean them up for you:
0241234567 241234567 233241234567 +233 24 123 4567
Responses always use the international form without the plus, like 233241234567.
Numbers we can't read are skipped and listed back to you in skipped.
Send SMS
Send one message to one number or to up to 10,000 at once. Large sends go out in the background, and each number gets its own delivery status.
Body
An approved sender ID on your account, like AKOSUAKTCH.
Phone numbers. Duplicates are sent once.
Up to 1,530 characters. {name} is replaced with each contact's first name from
your saved contacts.
Schedule it for later, like 2026-12-24T09:00:00Z. Leave it out to send now.
List messages
Your most recent messages, newest first, with their delivery status.
Query
Only the messages from one send, using the batch_id it returned.
How many to return. Default 50, at most 1,000.
Balance
How many SMS credits you have left. One credit sends one part of one message.
Send a code
We make a random code, text it to the number and remember it. You never store or compare codes yourself. A new code for the same number cancels the old one.
Body
Where to send the code.
An approved sender ID. Defaults to your first approved one.
Digits in the code, 4 to 8. Default 6.
How long the code works, 1 to 30. Default 5.
Your own wording. Must contain {code}; {minutes} is optional.
Check a code
Check what your user typed. A code works once, for its expiry time, with at most 5 wrong tries.
Body
What the user typed.
From the send response. Or send phone to check the latest code for that number.
When it doesn't match
You still get 200, with verified: false and a reason:
| reason | Meaning |
|---|---|
wrong_code | Doesn't match. attempts_left says how many tries remain. |
expired | Too late, or a newer code was sent. Send a new one. |
already_used | This code was already accepted once. |
too_many_attempts | 5 wrong tries. Send a new code. |
not_found | No code was sent to that number or id. |
Message statuses
| status | Meaning |
|---|---|
scheduled | Waiting for its send_at time. |
queued | Accepted, about to go to the network. |
pending | With the network, waiting for the delivery report. |
delivered | The phone received it. |
failed, expired, rejected | The network couldn't deliver it. The credit goes back on your balance automatically. |
Parts and billing
A plain-text SMS holds 160 characters. Longer messages are split into parts of 153, and each part uses one credit. An emoji or a character outside the standard SMS alphabet switches the whole message to a format that holds 70 characters (67 per part when split).
Credit is taken when you send and given back for anything the network fails to deliver. The
credits field in each send response says exactly what was used.
Prices are on the pricing section. Credit never expires.
Errors
Errors come back with a status code and a plain sentence you can show to a person:
{ "error": "Not enough credit: this needs 500 and you have 120." }| Status | When |
|---|---|
400 | Something in the request is missing or wrong. |
401 | The API key is missing, wrong or replaced. |
402 | Not enough credit for this send. |
404 | That path doesn't exist. |
429 | Too many requests. Wait a moment and try again. |
5xx | Our side. It's safe to retry after a few seconds. |
Retry only on network errors and 5xx. A 4xx will fail the same way again.
AI agent brief
Building with Claude Code, Cursor or Copilot? Download one markdown file with these rules, every endpoint and a working client, and hand it to your agent.