Skip to main content

Requests and retries

Every Ponitor API uses JSON over HTTPS with your API key in a header. Each request carries your own externalId, so you can retry safely.

Format​

  • Use HTTPS and the base URL of the API you're calling.
  • Send JSON with Content-Type: application/json. Responses are JSON.
  • Send your key in the apiKey header. See API keys and base URLs.
  • Times are ISO 8601 in UTC, such as 2026-10-05T09:30:00.000Z.
  • Money is in US dollars, as a number. 0.05 is five cents.

Phone numbers​

Write numbers without spaces or dashes. The two APIs take different forms:

  • Messaging API: international format, with or without the +: +231770000000 or 231770000000. Not a leading 0.
  • Airtime API: digits only: 231770000000, or the local form 0770000000. A + is refused.

Messages show numbers with the +, in responses and in webhooks. Airtime purchases and USSD requests show them without it.

Retry safely with externalId​

Every request that sends a message or makes a purchase carries an externalId: your own reference, such as an order number. It must be unique within your team. The Messaging API takes up to 64 characters. The Airtime API takes up to 30 letters, digits, _, . or -, so a UUID (36 characters) is too long there.

If a request times out, you can't tell whether Ponitor received it. Send it again with the same externalId. If the first request went through, you get that message or purchase back with 200 OK. Nothing is sent or charged a second time.

Your serverPonitorYour request times out. Did it go through?POST, externalId "order-42"×201 Created (lost on the way)Same POST, externalId "order-42"200 OK: the original, not sent or charged again
The first response never arrived, so the server sends the same request again. Ponitor recognises the externalId and returns what it already did.
  • Use a new externalId for each new request. Reuse one only to retry the same request. If you send different content with a used externalId, you get the original back.
  • externalIds are scoped to your team. They never clash with another team's.
  • Retry after a timeout, a 429 or a 5xx. Wait longer before each attempt, for example 1, 2, 4 and 8 seconds.
  • Don't retry a 400 unchanged. Fix the request first.

Responses​

A Messaging API response wraps the object in a key.

{ "message": { "id": "e2c38865-dc0a-4299-baef-c07a9bfa9c33", "status": "QUEUED" } }

An Airtime API response is the object itself. Each endpoint's page shows its exact response.

An error has an error object with a code that never changes. A request that fails validation lists each field at fault in details.

{
"error": {
"type": "validation_error",
"code": "E01001",
"name": "ValidationError",
"message": "The request has 1 problem.",
"doc_url": "https://docs.ponitor.com/api/errors#E01001",
"request_id": "c1f0b7a2-5e1d-4c8e-9a0b-7d6e5f4c3b2a",
"param": "externalId",
"details": [{ "param": "externalId", "message": "externalId is required" }]
},
"message": "The request has 1 problem."
}

Branch on error.code, not the message text. The text can change. Errors lists every code.

Timeouts and limits​

  • Wait 30 seconds before you treat a request as timed out. Most requests answer in under a second.
  • Too many requests in a minute return 429 Too Many Requests. Wait and retry as described above. See Rate limits.
  • Use a webhook to follow a message or a purchase instead of polling.