---
title: Send airtime
description: Top up any Nigerian number on MTN, Airtel, Glo or 9mobile.
group: api
order: 1
method: POST
path: /api/v1/airtime
---

Routes the top-up through a line that can send it on the network and answers with the final state.

## Body

| Field | Type | Required | Notes |
| --- | --- | --- | --- |
| `product_code` | string | yes | The network's airtime product: `MTN-VTU`, `AIRTEL-VTU`, `GLO-VTU` or `9MOBILE-VTU`. See [List plans](/docs/api/list-data-plans) |
| `amount` | number | yes | Naira, at most two decimals, within the product's `min_amount` and `max_amount` |
| `phone_number` | string | yes | Nigerian number, `08012345678` or `+2348012345678`. `phone` is accepted as an alias |
| `client_reference` | string | no | Your own reference, 1 to 128 characters, unique per mode |

Send an `Idempotency-Key` header with every request. You can also send `network` (such as `mtn`) on its own instead of `product_code`, and the network's airtime product is used.

## Waiting for the result

By default the call stays open until the sale is final, up to a limit set by us, and answers `200`. If the sale is still on its way when the limit is reached, it answers `202` with the sale as it stands (`status` not final yet). Add `?wait=0` to get `202` at once and follow the sale by webhook or [Get a transaction](/docs/api/get-transaction).

## Request

```bash
curl https://api.simconnectng.com/api/v1/airtime \
  -H "Authorization: Bearer $SIMCONNECT_KEY" \
  -H "Idempotency-Key: order_1042" \
  -H "Content-Type: application/json" \
  -d '{ "product_code": "MTN-VTU", "amount": 500, "phone_number": "08012345678", "client_reference": "order_1042" }'
```

## Response

```json
{
  "success": true,
  "data": {
    "id": "0192f4c1-a7e8-7b6f-9d2c-3e5a7b9d1f30",
    "reference": "txn_0192f4c1a7e84b6f9d2c3e5a7b9d1f30",
    "client_reference": "order_1042",
    "mode": "live",
    "status": "successful",
    "product_code": "MTN-VTU",
    "network": "mtn",
    "service": "airtime",
    "destination": "+234********78",
    "amount": 500.00,
    "price": 2.00,
    "failure_code": null,
    "failure_message": null,
    "created_at": "2026-10-06T12:04:01Z",
    "completed_at": "2026-10-06T12:04:03Z"
  },
  "message": "Transaction successful",
  "code": "OK"
}
```

A final `status` is `successful` or `failed`. Any other, such as `pending`, finishes later and you hear about it by webhook. `amount` is the airtime sent; `price` is the flat fee your wallet pays for the sale. `destination` is always masked. The figures shown here are placeholders.

## Error

```json
{ "success": false, "data": null, "message": "Insufficient wallet balance", "code": "WALLET_INSUFFICIENT_FUNDS" }
```
