Airtime Async
Async: the API stores the transaction, enqueues it, and returns immediately with HTTP 200 and response_code 02 (pending). Poll status until final.
| Route | Notes |
|---|---|
POST /v1/transactions | product: airtime or data |
POST /v1/transactions/airtime/async | Forces product: airtime |
POST /v1/transactions/data/async | Forces product: data |
For sync creates (final outcome in the create response), see Airtime.
Bill products (ELECTRICITY, CABLE, BETTING) are sync on POST /v1/transactions — see Bill payments overview.
Request body
| Field | Required | Description |
|---|---|---|
merchant_code | Yes | Your merchant profile |
customer_msisdn | Yes | Subscriber number (234… or 080…) |
network | Yes | mtn, glo, airtel, 9mobile |
product | Yes | airtime, data, ELECTRICITY, CABLE, or BETTING |
amount | Yes | Amount in Naira (string) |
client_request_id | Yes | Your unique idempotency key |
plan_code | Data & bills | Data: prefixed code from Data plans (e.g. MTN-8). Bills: catalog id from Electricity, Cable TV, or Betting. Legacy tariff/product ids still work for existing clients. |
Create and status responses use the same envelope: status, response_code, response_message, and data. See Field conventions.
Buy airtime (async)
curl -X POST "https://api.breezeinnovations.io/v1/transactions" \
-H "Content-Type: application/json" \
-H "X-Merchant-Key: mk_your_key_id" \
-H "X-Merchant-Secret: your_issued_secret" \
-d '{
"merchant_code": "YOUR_MERCHANT",
"customer_msisdn": "2348012345678",
"network": "mtn",
"product": "airtime",
"amount": "100",
"client_request_id": "req-20260517-003"
}'HTTP 200 — pending (poll status):
{
"status": "pending",
"response_code": "02",
"response_message": "Pending",
"data": {
"internal_reference": "019262ab-7c4d-7000-8000-000000000001",
"msisdn": "2348012345678",
"product": "airtime",
"request_id": "req-20260517-003",
"network": "MTN",
"amount": "100",
"plan": "",
"merchant_id": 10
}
}Check status
Use after async creates, or to re-fetch an outcome. Pass the same client_request_id you sent on create as a query parameter (not in the URL path).
GET /v1/transactions/status?client_request_id={client_request_id}| Query | Required | Description |
|---|---|---|
client_request_id | Yes* | Your idempotency key from the create call (recommended) |
request_id | Alt. | Same value — matches the request_id field in responses |
request_ref | Alt. | Same value — legacy alias for client_request_id |
*One of client_request_id, request_id, or request_ref is required.
Example — poll after an async airtime create:
curl "https://api.breezeinnovations.io/v1/transactions/status?client_request_id=req-20260517-003" \
-H "X-Merchant-Key: mk_your_key_id" \
-H "X-Merchant-Secret: your_issued_secret"If you used sync create (Airtime) and received response_code 00 or 01, you already have the final outcome — status polling is optional.
HTTP 400 — missing query param:
{
"status": "error",
"code": 400,
"message": "client_request_id, request_id, or request_ref query parameter is required"
}HTTP 200 — same envelope as create:
{
"status": "success",
"response_code": "00",
"response_message": "Successful",
"data": {
"internal_reference": "019262ab-7c4d-7000-8000-000000000001",
"msisdn": "2348012345678",
"product": "airtime",
"request_id": "req-20260517-003",
"network": "MTN",
"amount": "100",
"merchant_id": 10,
"merchant_name": "YOUR_MERCHANT",
"created_at": "2026-05-17 10:30:00",
"updated_at": "2026-05-17 10:31:15"
}
}updated_at is the last time the transaction row changed (for example when an MTN status check moves it from pending to success/failed). List transactions returns the same fields on each row.
response_code | status | Meaning |
|---|---|---|
00 | success | Completed successfully |
01 | failed | Failed |
02 | pending | Still processing |
List transactions
GET /v1/transactions| Query | Default | Description |
|---|---|---|
page | 1 | Page number |
limit | 10 | Page size |
msisdn | — | Filter by subscriber |
network | — | Filter by network name |
status | — | Filter by status code (integer) |
curl "https://api.breezeinnovations.io/v1/transactions?page=1&limit=20" \
-H "X-Merchant-Key: mk_your_key_id" \
-H "X-Merchant-Secret: your_issued_secret"HTTP 200:
{
"status": "success",
"data": [],
"pagination": {
"total": 0,
"page": 1,
"size": 20,
"total_pages": 0
}
}Idempotency
Reusing the same client_request_id for a merchant returns 422. Query status instead of resubmitting.