KemDataplus API

Integrate data bundle purchasing directly into your application. Place orders, check balances, and track deliveries programmatically.

v1.0 Bearer Token JSON
Overview

The KemDataplus API lets you buy data bundles across all major networks (MTN, Telecel, AirtelTigo) programmatically. All requests use JSON over HTTPS and are authenticated with a Bearer token.

🔐

Authentication

All endpoints require an API key in the Authorization header. Generate yours from Profile → Settings.

💰

Wallet-Based

Orders are deducted from your pre-funded wallet balance. Top up your wallet before placing orders. Insufficient balance returns a clear error.

📦

Instant Delivery

Orders are dispatched automatically to providers. Track status per order — PENDING → PROCESSING → COMPLETED.

Base URL

All API requests should be made to: Loading...

All request and response bodies are JSON. Set Content-Type: application/json and Accept: application/json on every request.

Quick Start

Three steps to place your first order.

1

Fetch available bundles to get a bundleId

cURL
curl '/api/bundles?network=MTN'
Response (excerpt)
[
  { "id": "cm3x9a1b2c3d4e5f6", "name": "MTN 5GB", "dataAmount": "5GB", "basePrice": 8.50 },
  { "id": "cm3x9b7c8d9e0f1a2", "name": "MTN 10GB", "dataAmount": "10GB", "basePrice": 15.00 }
]
2

Place an order using the bundleId and recipient phone

cURL
curl --request POST '/api/order-groups' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9' \
--header 'Content-Type: application/json' \
--data '{
  "items": [{ "bundleId": "cm3x9a1b2c3d4e5f6", "recipientPhone": "0241234567" }]
}'
Response
{
  "message": "Order created successfully",
  "order": { "orderId": "GRP-000105", "status": "PROCESSING", "totalAmount": 8.50 }
}
3

Poll the order status until COMPLETED

cURL
curl '/api/order-groups/GRP-000105' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9'
Response
{
  "id": "GRP-000105",
  "summaryStatus": "COMPLETED",
  "items": [{ "recipientPhone": "0241234567", "bundle": "MTN 5GB", "status": "COMPLETED" }]
}
Authentication

All protected endpoints require an API key in the Authorization header. Generate your key from the Profile → Settings page.

How to authenticate

Generate an API key from your Profile → Settings tab. It never expires — use it on every request without re-authenticating.

Header
Authorization: Bearer kdp_sk_a3f9c8d2...

Keep your API key secret. Revoke or regenerate it anytime from your profile page.

POST /api/auth/api-key/regenerate Generate / regenerate API key Auth required
Request
Response

No request body needed. Generates a new key and immediately invalidates the old one (if any). You can also do this from Profile → Settings in the dashboard.

cURL
curl --location --request POST '/api/auth/api-key/regenerate' \
--header 'Authorization: Bearer <your-token-or-existing-api-key>'
200 OK
JSON
{
    "apiKey": "kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9d3e6f2a1b4c7d9e3f6a2b5c8d1e4f7a"
}

Copy and store this key immediately. For security, the full value is only shown once per generation — but you can always regenerate a new one.

DELETE /api/auth/api-key Revoke API key Auth required
Request
Response

No request body needed. Permanently deletes your current API key. Any integrations using it will stop working immediately.

cURL
curl --location --request DELETE '/api/auth/api-key' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9'
200 OK
JSON
{
    "message": "API key revoked successfully."
}
POST /api/auth/login Login
Request
Response
FieldTypeRequiredDescription
emailstringRequiredYour account email address
passwordstringRequiredYour account password
cURL
curl --location '/api/auth/login' \
--header 'Content-Type: application/json' \
--data '{
    "email": "you@example.com",
    "password": "yourpassword"
}'
200 OK
JSON
{
    "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
    "user": {
        "id": "usr_abc123",
        "name": "Kwame Mensah",
        "email": "you@example.com",
        "role": "USER"
    }
}
401 Unauthorized
JSON
{
    "error": "Invalid email or password"
}
GET /api/auth/me Get current user Auth required
Request
Response

No request body required. Just include your Authorization header.

cURL
curl --location '/api/auth/me' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9'
200 OK
JSON
{
    "id": "usr_abc123",
    "name": "Kwame Mensah",
    "email": "you@example.com",
    "phone": "0241234567",
    "role": "USER"
}
Bundles

Retrieve the available data bundles. Use the bundle ID when placing orders.

GET /api/bundles List all bundles
Request
Response

No authentication required. Optional query parameters:

ParameterTypeRequiredDescription
networkstringOptionalFilter by network: MTN, Telecel, AirtelTigo
activebooleanOptionalSet true to return only active bundles
cURL
curl --location '/api/bundles'
200 OK
JSON
[
    {
        "id": "bundle_abc123",
        "name": "MTN 5GB",
        "network": "MTN",
        "dataAmount": "5GB",
        "validity": "1 Day",
        "basePrice": 8.50,
        "isActive": true,
        "outOfStock": false
    },
    { /* ... more bundles */ }
]
GET /api/bundles/network/:network Bundles by network
Request
Response
ParameterTypeRequiredDescription
networkstring (path)Required Supported networks:
MTN Telecel AirtelTigo
cURL
curl --location '/api/bundles/network/MTN'
200 OK
JSON
[
    {
        "id": "bundle_abc123",
        "name": "MTN 5GB",
        "network": "MTN",
        "dataAmount": "5GB",
        "validity": "1 Day",
        "basePrice": 8.50,
        "isActive": true
    }
]
Orders

Place single or bulk data bundle orders. Each order deducts from your wallet and is dispatched to the provider automatically.

Wallet Balance: Ensure your wallet has sufficient funds before placing an order. Orders are rejected immediately if your balance is too low. Top up via the dashboard.
POST /api/order-groups Place order Auth required
Request
Response
FieldTypeRequiredDescription
itemsarrayRequiredArray of order items (single or bulk)
items[].bundleIdstringRequiredBundle ID from /api/bundles
items[].recipientPhonestringRequiredRecipient's phone number (e.g. 0241234567)
idempotencyKeystringOptionalUnique key to prevent duplicate submissions on retry
cURL — Single Order
curl --location '/api/order-groups' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9' \
--header 'Content-Type: application/json' \
--data '{
    "items": [
        {
            "bundleId": "cm3x9a1b2c3d4e5f6",
            "recipientPhone": "0241234567"
        }
    ]
}'
cURL — Bulk Order
curl --location '/api/order-groups' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9' \
--header 'Content-Type: application/json' \
--data '{
    "items": [
        { "bundleId": "cm3x9a1b2c3d4e5f6", "recipientPhone": "0241234567" },
        { "bundleId": "cm3x9b7c8d9e0f1a2", "recipientPhone": "0557654321" }
    ],
    "idempotencyKey": "batch-20260715-001"
}'
201 Created
JSON
{
    "message": "Order created successfully",
    "order": {
        "orderId": "GRP-000042",
        "itemCount": 2,
        "isBatch": true,
        "totalAmount": 17.00,
        "status": "PROCESSING",
        "items": [
            {
                "itemNumber": 1,
                "reference": "ORD-000042-01",
                "bundle": "MTN 5GB",
                "recipientPhone": "0241234567",
                "totalPrice": 8.50
            }
        ]
    }
}
400 Insufficient Balance
JSON
{
    "error": "Insufficient wallet balance",
    "code": "INSUFFICIENT_BALANCE",
    "required": 17.00,
    "available": 5.50
}
GET /api/order-groups List my orders Auth required
Request
Response
ParameterTypeRequiredDescription
pageintegerOptionalPage number (default: 1)
limitintegerOptionalResults per page (default: 20, max: 100)
cURL
curl --location '/api/order-groups?page=1&limit=20' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9'
200 OK
JSON
{
    "orders": [
        {
            "id": "GRP-000042",
            "summaryStatus": "COMPLETED",
            "totalAmount": 8.50,
            "itemCount": 1,
            "createdAt": "2024-07-01T10:22:00.000Z"
        }
    ],
    "total": 47,
    "page": 1,
    "limit": 20
}
GET /api/order-groups/:id Get order status Auth required
Request
Response
ParameterTypeRequiredDescription
idstring (path)RequiredOrder group ID (e.g. GRP-000042)
cURL
curl --location '/api/order-groups/GRP-000042' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9'
200 OK
JSON
{
    "id": "GRP-000042",
    "summaryStatus": "COMPLETED",
    "totalAmount": 8.50,
    "createdAt": "2024-07-01T10:22:00.000Z",
    "items": [
        {
            "reference": "ORD-000042-01",
            "bundle": "MTN 5GB",
            "network": "MTN",
            "recipientPhone": "0241234567",
            "status": "COMPLETED",
            "price": 8.50
        }
    ]
}

Status values: PENDING → PROCESSING → COMPLETED / FAILED / CANCELLED

Wallet

Check your balance and view transaction history. Orders are funded from your wallet — make sure it has enough balance before placing orders.

GET /api/wallet/balance Get wallet balance Auth required
Request
Response

No request body required.

cURL
curl --location '/api/wallet/balance' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9'
200 OK
JSON
{
    "balance": 125.50
}
GET /api/wallet/transactions Transaction history Auth required
Request
Response
ParameterTypeRequiredDescription
pageintegerOptionalPage number (default: 1)
limitintegerOptionalResults per page (default: 20)
cURL
curl --location '/api/wallet/transactions?page=1&limit=20' \
--header 'Authorization: Bearer kdp_sk_a3f9c8d2e1b47f6a9c3d8e2f1b4a7c9'
200 OK
JSON
{
    "transactions": [
        {
            "id": "txn_xyz789",
            "type": "DEBIT",
            "amount": 8.50,
            "description": "Order GRP-000042",
            "balanceAfter": 117.00,
            "createdAt": "2024-07-01T10:22:00.000Z"
        }
    ],
    "total": 84,
    "page": 1
}
Error Codes

All errors return a JSON body with an error message and an optional code field for programmatic handling.

Error shape
{
    "error": "Human-readable message",
    "code": "MACHINE_READABLE_CODE"
}
401 Unauthorized
Missing or invalid Bearer token. Re-authenticate via /api/auth/login.
400 INSUFFICIENT_BALANCE
Wallet balance is too low to cover the order. Response includes required and available amounts.
400 INVALID_ITEM
Missing bundleId or recipientPhone in one of the order items.
403 WALLET_FROZEN
Your wallet has been frozen by an administrator. Contact support.
404 NOT_FOUND
The requested resource (bundle, order) does not exist or does not belong to you.
429 Too Many Requests
Rate limit exceeded. Back off and retry after a few seconds.
400 BUNDLE_OUT_OF_STOCK
The selected bundle is temporarily out of stock. Try another bundle or retry later.
500 Internal Error
Unexpected server error. If this persists, contact support with the request details.

Need help? Contact us at support@kemdataplus.com or visit your dashboard.