Introduction
Build your own data reselling business with the Rema Data API. Our secure, high-performance REST API allows you to programmatically purchase data bundles for MTN, Telecel, and AirtelTigo. Fulfillment is powered by our infrastructure for reliable delivery across all supported networks.
99.9% System Uptime
Engineered reliability for mission-critical businesses.
24/7 Developer Support
Direct access to our engineering team, day or night.
Free API Access
Get your API key instantly. No subscription fees or hidden charges.
Universal Coverage
Comprehensive support for all major networks across Ghana.
Developer Experience
RESTful endpoints, clean docs, and easy code examples.
Authentication
Authenticate your requests by including your secret API key in the X-API-KEY header.
Keep your key secret! Never share your API key in client-side code (browsers, mobile apps). Only use it from your backend server.
curl -X GET https://remadata.com/api/wallet-balance \
-H "X-API-KEY: rd_live_your_secret_key" \
-H "Content-Type: application/json"Sandbox
Build and test your whole integration before a single cedi moves. A test key never charges your wallet, never reaches a supplier and never creates a real order — but the responses have exactly the same shape as live ones.
Test keys start with rd_test_ and are free. Live keys start with rd_live_ and carry the one-time unlock fee.
Every sandbox response carries "sandbox": true, so a test key can never be mistaken for a live one in your logs. Sandbox references are prefixed TEST_.
curl -X POST https://remadata.com/api/developer/keys \
-H "Authorization: Bearer YOUR_DASHBOARD_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "name": "Local dev", "mode": "test" }'curl -H "X-API-KEY: rd_test_..." https://remadata.com/api/wallet-balance{
"status": "success",
"data": {
"sandbox": true,
"notice": "Sandbox response — no money moved and no order was placed.",
"balance": "1000.00",
"currency": "GHS"
}
}Forcing an outcome
The recipient number decides what happens, so you can exercise every branch of your code on demand — including the ones that are hard to reproduce in production.
curl -X POST https://remadata.com/api/v1/airtime \
-H "X-API-KEY: rd_test_..." \
-H "Content-Type: application/json" \
-H "Idempotency-Key: test-001" \
-d '{ "network": "mtn", "amount": 5, "recipient": "0240000000" }'{
"status": "error",
"code": "provider_failed",
"sandbox": true,
"message": "Sandbox: simulated upstream failure. Your wallet was not charged.",
"reference": "TEST_AIRTIME_9C2A1B4D",
"refunded": true
}Testing your webhook
Sandbox purchases fire real webhook deliveries to your registered endpoint, signed with your real secret. This is the point of the sandbox for most integrations: prove your signature check and your state machine work before you go live.
Register your endpoint with a test key, then drive each outcome with the numbers above to see order.completed, order.failed, order.refunded and order.waiting arrive in turn.
Going live
Swap rd_test_ for rd_live_. Nothing else changes — same URLs, same request bodies, same response shapes. Check that your code never branches on the sandbox flag before you do.
Get Available Bundles
Fetch a complete list of data bundles available for purchase. This endpoint returns your specific API Pricing, which may be lower than public prices.
Query Parameters
# Get all bundles
curl -X GET https://remadata.com/api/bundles \
-H "X-API-KEY: your_key"
# Filter by network
curl -X GET https://remadata.com/api/bundles?network=mtn \
-H "X-API-KEY: your_key"{
"status": "success",
"data": [
{
"network": "mtn",
"name": "1GB",
"volume": "1.00GB",
"volumeInMB": 1024,
"price": 5.50, // Your special API Price
"description": "Indomie bundle..."
},
{
"network": "telecel",
"name": "2GB",
"price": 10.00,
...
}
]
}Check Real-Time Price
Verify the exact cost of a specific data volume before purchasing. This is useful for dynamic pricing displays in your own app.
Body Parameters
curl -X POST https://remadata.com/api/get-cost-price \
-H "X-API-KEY: your_key" \
-H "Content-Type: application/json" \
-d '{"networkType":"mtn","volumeInMB":1024}'{
"networkType": "mtn",
"volumeInMB": 1024
}{
"status": "success",
"volume": "1024MB",
"network": "mtn",
"api_price": "5.50",
"currency": "GHS"
}{
"status": "error",
"message": "Missing required fields: volumeInMB, networkType"
}Purchase Data
Initiate a data purchase transaction. The amount will be deducted from your wallet instantly. successful responses return status: "pending" until delivery. If the provider cannot fulfill the order, your wallet is automatically refunded.
Body Parameters (Rema Data format)
Alternative format: phoneNumber, network, capacity (GB, e.g. 1 for 1GB). Nested payloads in data / body are also accepted.
const axios = require('axios');
await axios.post('https://remadata.com/api/buy-data', {
ref: 'MY_ORDER_001',
phone: '0551234567',
volumeInMB: 1024,
networkType: 'mtn'
}, {
headers: { 'X-API-KEY': 'your_key' }
});{
"status": "success",
"message": "Order placed successfully",
"data": {
"reference": "ORD_...",
"client_reference": "MY_ORDER_001",
"status": "pending",
"amount": 5.50,
"balance": "144.50",
"provider": "null"
}
}{
"status": "error",
"message": "Order failed: ... Your wallet has been refunded.",
"data": { "reference": "ORD_...", "refunded": true }
}Wallet Balance
Check your current account balance.
curl -H "X-API-KEY: key" https://remadata.com/api/wallet-balance{
"status": "success",
"message": "Wallet balance retrieved successfully",
"data": {
"balance": "150.00",
"currency": "GHS",
"wallet_id": "...",
"user_id": "...",
"last_transaction_at": "2025-02-27T..."
}
}Order History
1. Check Order Status
Quickly check the current status of an order using its reference number.
curl -X GET https://remadata.com/api/order-status/ORD_123456 \
-H "X-API-KEY: your_api_key"2. Get All Orders
Retrieve a paginated list of all your orders. By default, it returns the latest 15 orders.
curl -H "X-API-KEY: key" https://remadata.com/api/orders3. Get Order by ID
Fetch details of a single specific order using its unique ID.
curl -H "X-API-KEY: key" "https://remadata.com/api/orders?id=65b123..."4. Get by Reference
Find an order using your own custom reference number provided during purchase.
curl -H "X-API-KEY: key" "https://remadata.com/api/orders?ref_number=MY_REF_001"5. Advanced Filtering
Combine multiple filters to find specific subsets of orders.
curl -H "X-API-KEY: key" "https://remadata.com/api/orders?status=completed&network=mtn"curl -H "X-API-KEY: key" "https://remadata.com/api/orders?start_date=2025-01-01&end_date=2025-01-31"Order Status
Look up a single order by the reference returned when you bought it. Cheapest way to poll one order.
curl -H "X-API-KEY: key" https://remadata.com/api/order-status/ORD_123456{
"status": "success",
"data": {
"reference": "ORD_123456",
"status": "completed"
}
}Full Catalogue
Every bundle your key can buy, across both products. Buy any of them by posting its id to /api/buy-data.
cheap is our discounted route — lower price per GB, delivery can take longer, and a new recipient number may need one-time approval.instant is the operator's own package at face value, delivered immediately.
curl -H "X-API-KEY: key" "https://remadata.com/api/v1/catalogue?network=mtn&type=instant"{
"status": "success",
"message": "Catalogue retrieved",
"data": {
"count": 2,
"bundles": [
{
"id": "66f1a2...",
"name": "1GB",
"network": "mtn",
"type": "cheap",
"volume_mb": 1024,
"price": 4.5,
"currency": "GHS"
},
{
"id": "66f1b7...",
"name": "8683.07 MB",
"network": "mtn",
"type": "instant",
"volume_mb": 8683.07,
"price": 3,
"currency": "GHS"
}
]
}
}Airtime
Send airtime to any Ghana number. Charged to your wallet.
Always send an Idempotency-Key. If a request times out, retry with the same key and you get the original purchase back instead of topping the number up twice.
Your wallet is debited before the request goes out and refunded in the same call if it fails, so a failure never leaves you short.
curl -X POST https://remadata.com/api/v1/airtime \
-H "X-API-KEY: key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: order-10046" \
-d '{
"network": "telecel",
"amount": 10,
"recipient": "0201234567"
}'{
"status": "success",
"message": "Airtime sent",
"data": {
"reference": "ORD_993412",
"status": "completed",
"network": "telecel",
"recipient": "0201234567",
"amount": 10,
"fee": 0,
"total": 10,
"currency": "GHS"
}
}curl -H "X-API-KEY: key" "https://remadata.com/api/v1/airtime?amount=10"Delivery Status
How each network is delivering right now. Use it to set expectations before a customer buys, or to show a live status strip on your own site.
curl -H "X-API-KEY: key" https://remadata.com/api/v1/delivery-status{
"status": "success",
"data": {
"available": true,
"summary": "12 orders in the delivery queue. Typical wait is about 14 min.",
"networks": [
{
"network": "mtn",
"state": "ok",
"note": "Delivery is running normally.",
"typical_wait_seconds": 780,
"slow_wait_seconds": 2340,
"pending_orders": 12,
"last_delivered_at": "2026-10-23T18:34:15.752Z"
}
]
}
}AFA Registration
Register an applicant for AFA. Charged to your wallet.
Registration is not instant — it settles upstream over the following days. Poll with ?reference= or subscribe to webhooks.
curl -X POST https://remadata.com/api/v1/afa \
-H "X-API-KEY: key" \
-H "Content-Type: application/json" \
-d '{
"fullName": "John Doe",
"phoneNumber": "0241234567",
"idNumber": "GHA-123456789-0",
"dateOfBirth": "1990-01-15",
"town": "Accra",
"occupation": "Teacher",
"region": "Greater Accra",
"cropProduce": "Maize"
}'{
"status": "success",
"message": "AFA registration submitted",
"data": {
"reference": "AFA_558210",
"status": "pending",
"amount": 9.5,
"currency": "GHS"
}
}curl -H "X-API-KEY: key" "https://remadata.com/api/v1/afa?reference=AFA_558210"Webhooks
Register one HTTPS endpoint and we POST to it whenever one of your orders reaches a final state — no polling.
The signing secret is returned once, on registration. Store it immediately — it cannot be retrieved later.
An endpoint that rejects 20 deliveries in a row is deactivated. Re-register it once you have fixed it.
curl -X POST https://remadata.com/api/v1/webhooks \
-H "X-API-KEY: key" \
-H "Content-Type: application/json" \
-d '{ "url": "https://your-site.com/hooks/remadata" }'{
"status": "success",
"message": "Webhook registered",
"data": {
"id": "6710ab...",
"url": "https://your-site.com/hooks/remadata",
"events": ["order.completed", "order.failed", "order.refunded", "order.waiting"],
"active": true,
"secret": "whsec_9f2c..."
}
}{
"event": "order.completed",
"sent_at": "2026-10-23T18:40:02.114Z",
"data": {
"reference": "ORD_123456",
"status": "completed",
"network": "mtn",
"recipient": "0241234567",
"amount": 4.5,
"bundle": "1GB",
"created_at": "2026-10-23T18:31:10.004Z",
"completed_at": "2026-10-23T18:40:01.900Z"
}
}Verifying a delivery
Every call carries X-RemaData-Signature: an HMAC-SHA256 of the raw request body, keyed with your secret. Compare it before trusting the payload.
import crypto from "crypto";
// Use the raw body string, not the parsed object.
function isFromRemaData(rawBody, signatureHeader, secret) {
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(signatureHeader || "");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}curl -H "X-API-KEY: key" https://remadata.com/api/v1/webhooks
curl -X DELETE -H "X-API-KEY: key" "https://remadata.com/api/v1/webhooks?id=6710ab..."Errors
Every /api/v1 error carries a stable code. Branch on that, not on the message — wording may change.
{
"status": "error",
"code": "insufficient_balance",
"message": "Insufficient wallet balance. This top-up costs GHS 10.00.",
"required": 10,
"balance": 3.2
}