Products
Bulk SMS One-time codes Voice Soon Email Soon
Company
Pricing Developers Support

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.

KeyStarts withWhat it does
Livenk_live_Sends real messages and uses your credit.
Sandboxnk_test_Same requests and responses. Nothing is sent and nothing is charged.
Keep keys on your server. Never put a live key in a website, a mobile app or a public repository. Anyone holding it can send from your balance. If one leaks, make a new one in the dashboard and the old one stops working at once.

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

POST/v1/send

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

senderstringrequired

An approved sender ID on your account, like AKOSUAKTCH.

recipientsstring[]required

Phone numbers. Duplicates are sent once.

messagestringrequired

Up to 1,530 characters. {name} is replaced with each contact's first name from your saved contacts.

send_atISO 8601 date

Schedule it for later, like 2026-12-24T09:00:00Z. Leave it out to send now.

List messages

GET/v1/messages

Your most recent messages, newest first, with their delivery status.

Query

batch_idstring

Only the messages from one send, using the batch_id it returned.

limitnumber

How many to return. Default 50, at most 1,000.

Balance

GET/v1/balance

How many SMS credits you have left. One credit sends one part of one message.

Send a code

POST/v1/otp/send

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

phonestringrequired

Where to send the code.

senderstring

An approved sender ID. Defaults to your first approved one.

lengthnumber

Digits in the code, 4 to 8. Default 6.

expiry_minutesnumber

How long the code works, 1 to 30. Default 5.

messagestring

Your own wording. Must contain {code}; {minutes} is optional.

At most 5 codes to the same number in 10 minutes. Each code costs one credit, like any other SMS.

Check a code

POST/v1/otp/verify

Check what your user typed. A code works once, for its expiry time, with at most 5 wrong tries.

Body

codestringrequired

What the user typed.

otp_idstring

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:

reasonMeaning
wrong_codeDoesn't match. attempts_left says how many tries remain.
expiredToo late, or a newer code was sent. Send a new one.
already_usedThis code was already accepted once.
too_many_attempts5 wrong tries. Send a new code.
not_foundNo code was sent to that number or id.

Message statuses

statusMeaning
scheduledWaiting for its send_at time.
queuedAccepted, about to go to the network.
pendingWith the network, waiting for the delivery report.
deliveredThe phone received it.
failed, expired, rejectedThe 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." }
StatusWhen
400Something in the request is missing or wrong.
401The API key is missing, wrong or replaced.
402Not enough credit for this send.
404That path doesn't exist.
429Too many requests. Wait a moment and try again.
5xxOur 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.