Transactions
Create and inspect purchases. One endpoint covers airtime, data, voice, AFA, ECG, and future product types via the product field.
How to use
- Resolve catalog ids from GET /products (do not hard-code).
POST /transactionswithtransactions:create+ the product scope, a uniqueIdempotency-Key, and the fields for that product type.- Track status with
GET /transactions/{id},GET /transactions/{id}/status, or webhooks.
Product-specific walks: Airtime · Data · ECG · Voice & AFA.
Create transaction
Scopes: transactions:create plus the product scope (e.g. airtime:purchase).
POST
https://confident-elephant-309.convex.site/v1/transactionsRequest
curl -sS https://confident-elephant-309.convex.site/v1/transactions \ -H "Authorization: Bearer $KEY" \ -H "Idempotency-Key: 550e8400-e29b-41d4-a716-446655440000" \ -H "Content-Type: application/json" \ -d '{ "externalReference": "ORDER-123", "product": "airtime", "productId": "airtime-mtn", "amount": 5, "beneficiary": "0241234567" }'201 Created
{ "transaction": { "id": "511260", "reference": "511260", "status": "pending", "kind": "purchase", "environment": "sandbox" }, "purchase": { "id": "511260", "reference": "511260", "status": "pending", "kind": "purchase" }}Idempotency vs externalReference
| Field | Role |
|---|---|
Idempotency-Key | Prevents duplicate execution on retries; response is replayed |
externalReference | Your order / reconciliation id (unique per app + environment) |
Request body
| Field | Required | Description |
|---|---|---|
idempotencyKey | Yes* | Or Idempotency-Key header (UUID recommended) |
product | Yes | data | airtime | voice | afa | ecg | ecg_prepaid | ecg_postpaid |
productId | Usually | Partner code e.g. airtime-mtn (from GET /products) |
amount | When sold by amount | Major units (GHS) |
beneficiary | Airtime / data / voice | MSISDN e.g. 024… |
packageId | Data / AFA packages | Catalog package id; charged at catalog developer price |
meterNumber | ECG | After meter lookup |
meterId | ECG | From meters/lookup when required |
category | ECG | PREPAID | POSTPAID |
phoneNumber | ECG optional | Customer contact for utility |
externalReference | No | Your order id for reconciliation |
Get transaction
Scope: transactions:read
GET
https://confident-elephant-309.convex.site/v1/transactions/{id}Request
curl -sS https://confident-elephant-309.convex.site/v1/transactions/511260 \ -H "Authorization: Bearer $KEY"200 OK
{ "transaction": { "id": "511260", "reference": "511260", "status": "completed", "kind": "purchase", "environment": "sandbox", "amount": 1, "currency": "GHS", "beneficiary": "0241234567", "externalReference": "ORDER-123", "token": null, "errorCode": null, "customerMessage": null, "createdAt": 1793722011260, "completedAt": 1793722011394 }}Status poll
GET
https://confident-elephant-309.convex.site/v1/transactions/{id}/statusRequest
curl -sS https://confident-elephant-309.convex.site/v1/transactions/511260/status \ -H "Authorization: Bearer $KEY"200 OK
{ "id": "511260", "status": "completed", "reference": "511260"}Statuses include pending, processing, completed, failed. Prefer webhooks for final state.
Legacy alias
POST /purchases and GET /purchases/{id} behave like the transactions routes. New integrations should use /transactions.
Service guides: Airtime, Data, ECG, Voice & AFA.