v2 — the only live API

KiNG FLEXY GH
Developer API

Purchase data bundles programmatically. Integrate directly into your apps using your wallet balance and agent pricing.

Base URLhttps://api.kingflexygh.com/api/v2
Authentication Header
Authorization: kf_live_your_api_key_here

Ghana networks only. This API fulfils MTN, Telecel, AT-iShare, and AT-BigTime — Ghanaian numbers and Ghanaian networks exclusively. There is no support for international numbers, foreign telecom networks, or any country outside Ghana.

Section:Authentication

On this page

1Authentication

All API requests must include your API key in the Authorization header — no Bearer prefix required.

Authorization: kf_live_your_api_key_here
⚠️

Important: Your API key is shown only once when generated. Store it securely — losing it requires generating a new key, which permanently revokes the old one.

Getting Your API Key

  1. 1Log in to your KingFlexyGh account (agent role required)
  2. 2Navigate to Dashboard → Developer API
  3. 3Click Generate API Key and accept the policy
  4. 4Copy and store the key — it will not be shown again
  5. 5Wait for admin approval (status: pending → active)

2Response Format

All responses follow a consistent JSON structure:

Success

{
  "success": true,
  "data": { ... },
  "meta": {
    "timestamp": "2026-...",
    "version": "v2"
  }
}

Error

{
  "success": false,
  "error": {
    "code": 400,
    "message": "..."
  }
}

3Endpoints

Five endpoints — all require a valid API key in the Authorization header.

GET/api/v2/packagesList all available data packages with pricing for your account role. Call this first to discover valid network and size combinations.

List all available data packages with pricing for your account role. Call this first to discover valid network and size combinations.

Query Parameters

networkstringoptionalFilter by network: MTN, Telecel, AT-iShare, AT-BigTime (case-sensitive)
size_gbnumberoptionalFilter by exact GB size e.g. 5

Response

{
  "success": true,
  "data": {
    "packages": [
      {
        "id": "uuid-...",
        "network": "MTN",
        "size": "5GB",
        "volume_gb": 5,
        "price": 4.50,
        "currency": "GHS"
      }
    ],
    "total": 12
  }
}
  • →Price is your role-specific price (agent, dealer, or standard customer).
  • →Only packages with is_available = true are returned.
  • →Use this to validate network/size combinations before placing orders.

Code Sample

cURL
# All packages
curl -X GET https://api.kingflexygh.com/api/v2/packages \
  -H "Authorization: kf_live_your_api_key_here"

# Filter by network
curl -X GET "https://api.kingflexygh.com/api/v2/packages?network=MTN" \
  -H "Authorization: kf_live_your_api_key_here"

# Filter by network + size
curl -X GET "https://api.kingflexygh.com/api/v2/packages?network=MTN&size_gb=5" \
  -H "Authorization: kf_live_your_api_key_here"
POST/api/v2/data/purchasePurchase a single data bundle for a recipient phone number. Deducts from your wallet instantly.

Purchase a single data bundle for a recipient phone number. Deducts from your wallet instantly.

Request Body

{
  "network": "MTN",
  "volume_gb": 5,
  "recipient": "0551617309",
  "reference": "order_001"
}

Response

{
  "success": true,
  "data": {
    "order_id": "uuid-...",
    "reference": "order_001",
    "status": "pending",
    "network": "MTN",
    "size": "5GB",
    "recipient": "0551617309",
    "price": 4.50,
    "new_balance": 120.50
  }
}
  • →reference is your idempotency key — sending the same reference twice returns the existing order without double-charging.
  • →status is usually "pending", but MAY be "queued" if the recipient number still needs registration on our network — it auto-releases to pending and is fulfilled shortly after. Poll GET /api/v2/orders/{reference} to track it.
  • →MTN purchases MAY also return 409 if the recipient number isn't yet whitelisted with our supplier (only applies when this optional gate is enabled by an admin) — message reads "This number isn't yet registered to receive MTN data. Please try again in 24 hours." Retrying after ~24 hours usually succeeds once the number is whitelisted.
  • →network must be one of: MTN, Telecel, AT-iShare, AT-BigTime (case-sensitive).
  • →volume_gb must match an available package. Use GET /packages to confirm.
  • →recipient must be a valid Ghana number: 0XXXXXXXXX (10 digits, starts with 0).

Code Sample

cURL
curl -X POST https://api.kingflexygh.com/api/v2/data/purchase \
  -H "Authorization: kf_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "network": "MTN",
    "volume_gb": 5,
    "recipient": "0551617309",
    "reference": "order_001"
  }'
POST/api/v2/data/bulkPurchase up to 100 data bundles in a single batch. A validation failure (invalid network, package not found, out of stock) rejects the whole batch and nothing is charged; the one exception is MTN recipients not yet whitelisted with our supplier — those orders are skipped individually while the rest of the batch is placed and charged normally.

Purchase up to 100 data bundles in a single batch. A validation failure (invalid network, package not found, out of stock) rejects the whole batch and nothing is charged; the one exception is MTN recipients not yet whitelisted with our supplier — those orders are skipped individually while the rest of the batch is placed and charged normally.

Request Body

{
  "orders": [
    {
      "network": "MTN",
      "volume_gb": 5,
      "recipient": "0551617309",
      "reference": "b_001"
    },
    {
      "network": "Telecel",
      "volume_gb": 2,
      "recipient": "0201234567",
      "reference": "b_002"
    }
  ]
}

Response

{
  "success": true,
  "data": {
    "orders_placed": 2,
    "total_cost": 7.00,
    "new_balance": 113.50,
    "orders": [
      { "order_id": "...", "reference": "b_001", "status": "pending" }
    ],
    "skipped": []
  }
}
  • →Maximum 100 orders per batch request.
  • →Still atomic for network/package validation failures (invalid network, package not found, out of stock) — one bad order in the array rejects the whole batch and nothing is charged.
  • →MTN orders to a recipient not yet whitelisted with our supplier are the one exception: they are skipped individually — not charged, not created — while the rest of the batch is placed normally. Only applies when this optional gate is enabled by an admin.
  • →skipped is an array of { recipient, reason }, one entry per order skipped for the whitelist reason above — cross-reference it against your original orders array since skipped orders have no reference or order_id.
  • →Each order in the array follows the same rules as single purchase.

Code Sample

cURL
curl -X POST https://api.kingflexygh.com/api/v2/data/bulk \
  -H "Authorization: kf_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "orders": [
      {"network":"MTN","volume_gb":5,"recipient":"0551617309","reference":"b_001"},
      {"network":"Telecel","volume_gb":2,"recipient":"0201234567","reference":"b_002"}
    ]
  }'
GET/api/v2/wallet/balanceRetrieve your current wallet balance in GHS. Use before large orders to verify you have sufficient funds.

Retrieve your current wallet balance in GHS. Use before large orders to verify you have sufficient funds.

Response

{
  "success": true,
  "data": {
    "balance": 124.50,
    "currency": "GHS"
  }
}
  • →Top up your wallet via the web dashboard at kingflexygh.com/dashboard/wallet.
  • →Check balance before bulk orders to prevent partial failures due to insufficient funds.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/wallet/balance \
  -H "Authorization: kf_live_your_api_key_here"
GET/api/v2/orders/{reference}Check the fulfillment status of an order using the reference code you provided when placing it.

Check the fulfillment status of an order using the reference code you provided when placing it.

Response

{
  "success": true,
  "data": {
    "order_id": "uuid-...",
    "reference": "order_001",
    "status": "completed",
    "network": "MTN",
    "size": "5GB",
    "recipient": "0551617309",
    "price": 4.50,
    "source": "api",
    "created_at": "2026-..."
  }
}
  • →Use the same reference you passed when calling /data/purchase or /data/bulk.
  • →Status lifecycle: pending | queued → processing → completed | failed | refunded.
  • →pending — order accepted and awaiting dispatch to the network.
  • →queued — the recipient MTN number is not yet registered with our network provider, so the order is held (not dispatched); it auto-releases to pending and is fulfilled once registration completes, usually within a short period.
  • →processing — dispatched to the network and being fulfilled.
  • →completed — bundle delivered successfully.
  • →failed — the order could not be fulfilled.
  • →refunded — the order was refunded to your wallet / original payment method.
  • →Poll this endpoint after placing an order to confirm delivery.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/orders/your_reference_here \
  -H "Authorization: kf_live_your_api_key_here"

4Account & Role

Check your own role and, if it's time-limited, how many days are left — no support ticket needed.

GET/api/v2/account/roleReturns your current role and, for dealer/agent, the days remaining before it lapses.

Returns your current role and, for dealer/agent, the days remaining before it lapses.

Response

{
  "success": true,
  "data": {
    "role": "dealer",
    "is_active": true,
    "is_permanent": false,
    "expires_at": "2026-...",
    "days_remaining": 12
  }
}
  • →is_permanent: true and expires_at: null means a lifetime dealer/agent, or a plain customer account — there is nothing to expire.
  • →is_active becomes false the moment expires_at passes, even though role in the users table has not changed yet — the platform prices you as a customer from that exact moment on every endpoint, not just this one.
  • →Rate limit: 30/min.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/account/role \
  -H "Authorization: kf_live_your_api_key_here"

5Airtime (v2)

Send MTN, Telecel, or AT airtime to a beneficiary at face value — no fee — on behalf of your customers, and earn a share of KiNG FLEXY GH's provider commission on every top-up. This endpoint only accepts a Commission Services key (prefix kf_cs_live_...); a standard key is rejected with 403.

POST/api/v2/airtime/purchaseSend airtime to a beneficiary at face value from your wallet. Auto-dispatches in the background — poll GET /airtime/orders/{reference} for the final status.

Send airtime to a beneficiary at face value from your wallet. Auto-dispatches in the background — poll GET /airtime/orders/{reference} for the final status.

Request Body

{
  "network": "MTN",
  "beneficiary_phone": "0551617309",
  "amount": 10,
  "reference": "air_001"
}

Response

{
  "success": true,
  "data": {
    "order_id": "uuid-...",
    "reference": "air_001",
    "status": "pending",
    "network": "MTN",
    "beneficiary_phone": "0551617309",
    "airtime_amount": 10,
    "fee_amount": 0,
    "total_paid": 10,
    "new_balance": 90
  }
}
  • →reference is your idempotency key (3–100 chars) — a repeat with the SAME reference and body returns the existing order instead of charging again; a reused reference against a DIFFERENT order returns 409 and your wallet is not charged.
  • →fee_amount is always 0 — the beneficiary receives the full amount at face value; your earnings come from a share of KiNG FLEXY GH's own provider commission, credited to your Commission Wallet once the order completes, not deducted from this transaction.
  • →Rate limit: 10/min.

Code Sample

cURL
curl -X POST https://api.kingflexygh.com/api/v2/airtime/purchase \
  -H "Authorization: kf_cs_live_your_commission_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "network": "MTN",
    "beneficiary_phone": "0551617309",
    "amount": 10,
    "reference": "air_001"
  }'
GET/api/v2/airtime/ordersList your most recent airtime orders.

List your most recent airtime orders.

Response

{
  "success": true,
  "data": {
    "orders": [ { "order_id": "uuid-...", "reference": "air_001", "status": "completed", "network": "MTN", "airtime_amount": 10 } ]
  }
}
  • →Returns at most 30 records, newest first. Rate limit: 30/min.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/airtime/orders \
  -H "Authorization: kf_cs_live_your_commission_key_here"
GET/api/v2/airtime/orders/{reference}Check the status of one airtime order using the reference you sent when placing it.

Check the status of one airtime order using the reference you sent when placing it.

Response

{
  "success": true,
  "data": {
    "order_id": "uuid-...",
    "reference": "air_001",
    "status": "refunded",
    "network": "MTN",
    "beneficiary_phone": "0551617309",
    "airtime_amount": 10,
    "reason": "The transaction could not be completed by the payment provider."
  }
}
  • →Rate limit: 30/min.
  • →Status flow: pending → processing → completed | failed | refunded. A definitive provider failure auto-refunds your wallet — status becomes "refunded" and `reason` is present with a short, fixed explanation (never raw provider text).

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/airtime/orders/air_001 \
  -H "Authorization: kf_cs_live_your_commission_key_here"

6Results Checker (v2)

Sell WAEC/BECE/WASSCE results checker vouchers. Same standard key.

Vouchers are returned directly in the purchase response — there is no separate "retrieve voucher" call. recipientPhone / recipientEmail are optional and have no fallback to your own account: omit both and KiNG FLEXY GH sends nothing — you own delivering the voucher to your customer.
GET/api/v2/resultschecker/typesList available voucher types with YOUR OWN role-based price and current stock.

List available voucher types with YOUR OWN role-based price and current stock.

Response

{
  "success": true,
  "data": {
    "types": [ { "type_id": "uuid-...", "name": "WAEC BECE", "price": 18, "available_count": 412, "is_active": true } ]
  }
}
  • →Rate limit: 30/min.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/resultschecker/types \
  -H "Authorization: kf_live_your_api_key_here"
POST/api/v2/resultschecker/purchaseBuy voucher(s). Stock is checked BEFORE your wallet is touched — insufficient stock is rejected upfront, never charged then refunded.

Buy voucher(s). Stock is checked BEFORE your wallet is touched — insufficient stock is rejected upfront, never charged then refunded.

Request Body

{
  "typeId": "uuid-of-a-type-from-GET-types",
  "quantity": 1,
  "reference": "rc_001",
  "recipientPhone": "0551617309",
  "recipientEmail": "customer@example.com"
}

Response

{
  "success": true,
  "data": {
    "order": { "id": "uuid-...", "reference": "rc_001", "status": "completed", "type_name": "WAEC BECE", "quantity": 1, "unit_price": 18, "total_paid": 18 },
    "vouchers": [ { "id": "uuid-...", "pin": "1234-5678-9012", "serial_number": "SN-000123" } ],
    "new_balance": 82
  }
}
  • →recipientPhone / recipientEmail are OPTIONAL. Pass either (or both) to also have KiNG FLEXY GH deliver the voucher by SMS/email as a courtesy — the vouchers array in this response is always the authoritative copy either way.
  • →reference is your idempotency key — a reused reference against a different order returns 409, wallet untouched.
  • →Rate limit: 10/min.

Code Sample

cURL
curl -X POST https://api.kingflexygh.com/api/v2/resultschecker/purchase \
  -H "Authorization: kf_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "typeId": "uuid-of-a-type-from-GET-types",
    "quantity": 1,
    "reference": "rc_001"
  }'
GET/api/v2/resultschecker/ordersList your most recent results checker orders.

List your most recent results checker orders.

Response

{
  "success": true,
  "data": {
    "orders": [ { "id": "uuid-...", "reference": "rc_001", "status": "completed", "type_name": "WAEC BECE", "quantity": 1 } ]
  }
}
  • →Returns at most 30 records, newest first. Rate limit: 30/min.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/resultschecker/orders \
  -H "Authorization: kf_live_your_api_key_here"
GET/api/v2/resultschecker/orders/{reference}Look up one order, including its vouchers again if you need to recover them.

Look up one order, including its vouchers again if you need to recover them.

Response

{
  "success": true,
  "data": {
    "order": { "id": "uuid-...", "reference": "rc_001", "status": "completed" },
    "vouchers": [ { "id": "uuid-...", "pin": "1234-5678-9012", "serial_number": "SN-000123" } ]
  }
}
  • →Rate limit: 30/min.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/resultschecker/orders/rc_001 \
  -H "Authorization: kf_live_your_api_key_here"

7AFA Registration (v2)

Register an MTN AFA agent on behalf of your customer. Same standard key.

POST/api/v2/afa/registerSubmit an AFA registration. Requires a valid Ghana Card and a supported region.

Submit an AFA registration. Requires a valid Ghana Card and a supported region.

Request Body

{
  "reference": "afa_001",
  "full_name": "Kwame Mensah",
  "phone": "0551617309",
  "id_type": "Ghana Card",
  "id_number": "GHA-123456789-0",
  "date_of_birth": "1995-04-12",
  "region": "Greater Accra",
  "location": "Madina"
}

Response

{
  "success": true,
  "data": {
    "order_id": "uuid-...",
    "reference": "afa_001",
    "status": "pending",
    "new_balance": 64.0
  }
}
  • →id_type must be exactly "Ghana Card"; id_number must match GHA-XXXXXXXXX-X.
  • →region must be one of the 16 official Ghana regions (Greater Accra, Ashanti, Western, Eastern, Central, Northern, Volta, Upper East, Upper West, Bono, Bono East, Ahafo, Savannah, North East, Oti, Western North).
  • →Applicant must be 18 or older — computed from date_of_birth.
  • →reference is your idempotency key. It is GLOBAL across all developers, not just your own account — a reused reference already taken by anyone returns 409, never a silent success.
  • →This carries Ghana Card KYC data — send it only over HTTPS, which is all this API accepts.
  • →Rate limit: 10/min.

Code Sample

cURL
curl -X POST https://api.kingflexygh.com/api/v2/afa/register \
  -H "Authorization: kf_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "reference": "afa_001",
    "full_name": "Kwame Mensah",
    "phone": "0551617309",
    "id_type": "Ghana Card",
    "id_number": "GHA-123456789-0",
    "date_of_birth": "1995-04-12",
    "region": "Greater Accra",
    "location": "Madina"
  }'
GET/api/v2/afa/ordersList your most recent AFA registrations.

List your most recent AFA registrations.

Response

{
  "success": true,
  "data": {
    "orders": [ { "id": "uuid-...", "reference": "afa_001", "status": "pending" } ]
  }
}
  • →Returns at most 30 records, newest first. Rate limit: 30/min.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/afa/orders \
  -H "Authorization: kf_live_your_api_key_here"
GET/api/v2/afa/orders/{reference}Check the status of one AFA registration.

Check the status of one AFA registration.

Response

{
  "success": true,
  "data": {
    "id": "uuid-...",
    "reference": "afa_001",
    "status": "processing"
  }
}
  • →Status lifecycle: pending → processing → completed | cancelled.
  • →Rate limit: 30/min.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/afa/orders/afa_001 \
  -H "Authorization: kf_live_your_api_key_here"

8SMS API

Send bulk and transactional SMS from your own systems — OTPs, order updates, campaigns — with per-recipient delivery tracking.

Business mode required. The SMS API is available once your business (domain + description) is registered and approved on the SMS dashboard. You then send under a default sender ID from our pool — or your own sender ID after network approval (Ghana Card required). SMS credits are purchased on the credits page; 1 credit = 1 SMS segment (160 GSM chars) per recipient. Generate your SMS API key from the SMS dashboard's API & Docs tab — it's separate from your general developer API key and activates immediately, no approval wait. SMS dashboard · Credits page
POST/api/v2/sms/sendSend an SMS to one or many recipients. Small sends (≤500 recipients) dispatch immediately and return per-send results; larger sends are queued and processed within a minute.

Send an SMS to one or many recipients. Small sends (≤500 recipients) dispatch immediately and return per-send results; larger sends are queued and processed within a minute.

Request Body

{
  "message": "Your order #123 is ready. Thank you!",
  "recipients": ["0551234567", "0209876543"],
  "sender": "AcmeGH",
  "reference": "order-123"
}

Response

{
  "success": true,
  "data": {
    "campaignId": "uuid-...",
    "status": "completed",
    "recipients": 2,
    "segments": 1,
    "creditsCharged": 2,
    "sender": "AcmeGH",
    "sent": 2,
    "failed": 0,
    "balance": 498
  }
}
  • →message: 3–1000 characters. Cost = SMS segments × recipients (GSM-7: 160 chars = 1 segment; unicode/emoji reduce this to 70).
  • →recipients: a string or array of Ghana numbers (0XXXXXXXXX or 233XXXXXXXXX), up to 10,000 per call. Duplicates are removed automatically.
  • →sender is optional — defaults to your account's sending identity. It MUST be one of your approved sender IDs or a pool sender (call GET /sms/senders); any other value is rejected with 400.
  • →reference is an optional idempotency key (≤100 chars): retrying with the same reference returns the original campaign instead of sending again or double-charging.
  • →Credits are debited up-front; provider-rejected messages are refunded automatically when the campaign settles.
  • →Content policy: telco transaction-message impersonation (fake MoMo receipts etc.) is blocked. Links to any domain are allowed for business accounts.
  • →HTTP 402 = insufficient SMS credits. HTTP 403 = wrong key type (use your SMS API key, not your general developer key) or account suspended. HTTP 429 = rate limited.

Code Sample

cURL
curl -X POST https://api.kingflexygh.com/api/v2/sms/send \
  -H "Authorization: kf_sms_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "Your order #123 is ready for pickup. Thank you!",
    "recipients": ["0551234567", "0209876543"],
    "sender": "AcmeGH"
  }'
GET/api/v2/sms/sendersList the sender IDs this API key may send under — your approved own sender IDs plus the shared pool senders. Use these exact values for the sender field.

List the sender IDs this API key may send under — your approved own sender IDs plus the shared pool senders. Use these exact values for the sender field.

Response

{
  "success": true,
  "data": {
    "mode": "business",
    "defaultSender": "AcmeGH",
    "senders": [
      { "sender": "AcmeGH", "type": "own", "isDefault": true },
      { "sender": "KFT SMS", "type": "pool", "isDefault": false }
    ]
  }
}
  • →type "own" = a sender ID approved for your business; "pool" = a shared platform sender any approved business may use.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/sms/senders \
  -H "Authorization: kf_sms_live_your_api_key_here"
GET/api/v2/sms/messages/{campaignId}Delivery status for a send. Returns the campaign summary, a delivery rollup, and per-recipient statuses (100 per page).

Delivery status for a send. Returns the campaign summary, a delivery rollup, and per-recipient statuses (100 per page).

Query Parameters

pagenumberoptionalZero-based page of per-recipient rows (100/page)
statusstringoptionalFilter rows: queued, sent, delivered, undelivered, failed, expired, rejected

Response

{
  "success": true,
  "data": {
    "campaign": {
      "id": "uuid-...",
      "sender_used": "AcmeGH",
      "recipients_count": 2,
      "segments": 1,
      "credits_charged": 2,
      "status": "completed",
      "created_at": "2026-..."
    },
    "delivery": { "delivered": 2 },
    "messages": [
      {
        "recipient": "233551234567",
        "status": "delivered",
        "status_updated_at": "2026-..."
      }
    ],
    "page": 0
  }
}
  • →Use the campaignId returned by POST /sms/send.
  • →Message statuses: queued → sent → delivered | undelivered | expired | rejected. failed = rejected by the provider at send time (refunded).
  • →Delivery reports arrive asynchronously from the network — poll this endpoint a few minutes after sending for final statuses.

Code Sample

cURL
curl -X GET "https://api.kingflexygh.com/api/v2/sms/messages/your_campaign_id?status=delivered" \
  -H "Authorization: kf_sms_live_your_api_key_here"
GET/api/v2/sms/campaignsList your recent SMS campaigns, newest first — a discovery endpoint that complements GET /sms/messages/{campaignId} for when you don't already have a campaign id on hand.

List your recent SMS campaigns, newest first — a discovery endpoint that complements GET /sms/messages/{campaignId} for when you don't already have a campaign id on hand.

Query Parameters

pagenumberoptionalZero-based page, 30 per page (default 0)
statusstringoptionalFilter: queued, processing, completed, failed, blocked
fromstringoptionalISO date — only campaigns created on/after this date
tostringoptionalISO date — only campaigns created on/before this date

Response

{
  "success": true,
  "data": {
    "campaigns": [
      {
        "id": "uuid-...",
        "status": "completed",
        "recipients_count": 2,
        "segments": 1,
        "credits_charged": 2,
        "sender_used": "AcmeGH",
        "source": "api",
        "scheduled_at": null,
        "created_at": "2026-..."
      }
    ],
    "page": 0
  }
}
  • →Returns 30 campaigns per page, newest first — pass page to walk further back, not to raise the page size.
  • →Use the returned id with GET /sms/messages/{campaignId} for per-recipient delivery detail.

Code Sample

cURL
curl -X GET "https://api.kingflexygh.com/api/v2/sms/campaigns?status=completed" \
  -H "Authorization: kf_sms_live_your_api_key_here"
GET/api/v2/sms/balanceYour SMS credit balance and account mode.

Your SMS credit balance and account mode.

Response

{
  "success": true,
  "data": {
    "credits": 498,
    "totalPurchased": 600,
    "totalUsed": 102,
    "mode": "business",
    "accountStatus": "active"
  }
}
  • →SMS credits are separate from your GHS wallet — buy bundles at kingflexygh.com/dashboard/sms/credits.
  • →Check balance before large campaigns; sends fail with HTTP 402 when credits are insufficient.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/sms/balance \
  -H "Authorization: kf_sms_live_your_api_key_here"

9Utility Bills (Commission)

Pay ECG, Ghana Water, DSTV, GOtv, or StarTimes bills at face value on behalf of your customers — and earn a share of KiNG FLEXY GH's provider commission on every payment.

Separate key required. These four endpoints only accept a Commission Services key (prefix kf_cs_live_...) — a standard key is rejected with 403. The reverse is also true: a Commission Services key is rejected with 403 on every other /api/v2/* endpoint (packages, data purchases, wallet, SMS, etc.).

Generate one from Dashboard → Developer API — no shop required. Your commission is paid into a dedicated Commission Wallet, separate from shop earnings. Like the standard key, it starts pending and needs admin approval before it works.

How the money moves: the bill's face value is debited from your main wallet when you call POST /pay. Once the order reaches completed, your commission_share_percent cut of the platform's commission is credited automatically to your Commission Wallet — transfer it instantly to your main or shop wallet, or withdraw it via Paystack Mobile Money.

GET/api/v2/utilities/billersFull biller catalog for utility bill payments — including currently disabled billers, so you can build your UI without hardcoding which ones are live.

Full biller catalog for utility bill payments — including currently disabled billers, so you can build your UI without hardcoding which ones are live.

Response

{
  "success": true,
  "data": {
    "billers": [
      {
        "key": "ecg",
        "label": "ECG Prepaid & Postpaid",
        "enabled": true,
        "account_label": "Meter number",
        "requires_phone": true,
        "lookup_by": "phone",
        "links_phone_to_account": true,
        "has_amount_due": true
      },
      {
        "key": "dstv",
        "label": "DSTV",
        "enabled": true,
        "account_label": "Smartcard number",
        "requires_phone": false,
        "lookup_by": "account",
        "links_phone_to_account": false,
        "has_amount_due": true
      }
    ],
    "min_amount": 1,
    "max_amount": 1000,
    "currency": "GHS"
  }
}
  • →key values are: ecg, ghana_water, dstv, gotv, startimes — pass this exact string as biller on /lookup and /pay.
  • →enabled is false for a biller currently switched off by an admin — still listed so your UI can grey it out instead of guessing.
  • →lookup_by tells you which field ecg needs on /lookup ("phone") vs every other biller ("account").
  • →requires_phone — whether /pay requires a customer phone for this biller (ecg, ghana_water). Note: /lookup accepts account alone for ecg (phone optional there).
  • →links_phone_to_account is true only for ecg — one phone can be linked to more than one meter, so always let the customer pick from the meters array /lookup returns.
  • →min_amount / max_amount are the live, admin-configurable limits enforced by /pay — read them from here instead of hardcoding GHS 1–1000.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/utilities/billers \
  -H "Authorization: kf_cs_live_your_commission_key_here"
GET/api/v2/utilities/lookupVerify an account before paying. Always show your customer the returned name (or, for ECG, the linked meters) and get their confirmation before calling /pay.

Verify an account before paying. Always show your customer the returned name (or, for ECG, the linked meters) and get their confirmation before calling /pay.

Query Parameters

billerstringOne of: ecg, ghana_water, dstv, gotv, startimes
accountstringMeter/smartcard/account number, max 30 chars. Required for every biller, including ecg — for ecg pass the phone number here too if you have no separate meter number, since the query actually runs on phone.
phonestringoptionalCustomer phone, max 30 chars. Required for ghana_water. For ecg, this is what the lookup actually queries by — supply it, not just account.

Response

{
  "success": true,
  "data": {
    "account_name": "KWAME MENSAH",
    "account_number": "7041234567",
    "amount_due": 245.80,
    "bouquet": null,
    "meters": []
  }
}
  • →ECG's shape differs from every other biller: account_name, account_number, amount_due and bouquet are always null — the real result is meters: [{ "name": "KWAME MENSAH", "meterNumber": "3701234567", "outstanding": 245.8 }, ...]. One phone can list several meters; let the customer choose the right one.
  • →amount_due can be negative — that means the customer has a credit balance, not a bill due.
  • →404 = account/meter/smartcard not found (bad number). 502 = the billing provider is temporarily unreachable — retry shortly, do not treat as "not found".

Code Sample

cURL
# DSTV — query by smartcard number
curl -X GET "https://api.kingflexygh.com/api/v2/utilities/lookup?biller=dstv&account=7041234567" \
  -H "Authorization: kf_cs_live_your_commission_key_here"

# ECG — query by phone (account is still required; pass the same number)
curl -X GET "https://api.kingflexygh.com/api/v2/utilities/lookup?biller=ecg&phone=0551617309&account=0551617309" \
  -H "Authorization: kf_cs_live_your_commission_key_here"

reference on /pay is a pure idempotency key, not a distinct-payment key. Reusing the same reference — even with a different biller, account, or amount — returns the details of the ORIGINAL order and never charges you again; it does not re-validate against the new values you sent. Use a unique reference for every distinct bill. Reuse the same reference ONLY to safely retry the exact same payment (e.g. after a network timeout).

POST/api/v2/utilities/payPay a bill at face value from your wallet. Auto-dispatches to the biller in the background — poll GET /orders/{reference} for the final status.

Pay a bill at face value from your wallet. Auto-dispatches to the biller in the background — poll GET /orders/{reference} for the final status.

Request Body

{
  "biller": "dstv",
  "account": "7041234567",
  "amount": 65.00,
  "reference": "bill_dstv_7041234567_01"
}

Response

{
  "success": true,
  "data": {
    "reference": "UTIL-DSTV-3f9a2b1c4d5e6f70",
    "order_id": "uuid-...",
    "status": "pending",
    "biller": "dstv",
    "account": "7041234567",
    "amount": 65.00,
    "commission_share_percent": 40,
    "new_balance": 435.00
  }
}
  • →reference is a pure idempotency key — see the callout above. It is optional, 1–64 chars of letters, numbers, dot, underscore or hyphen.
  • →Save the reference from the RESPONSE, not the one you sent — it is our own generated code (UTIL-<BILLER>-<random>) and is what GET /orders/{reference} expects.
  • →On an idempotent replay (reused reference), the response is smaller: { reference, order_id, status, already_processed: true } — no biller/account/amount/commission_share_percent/new_balance, since nothing new happened.
  • →phone is required for ecg and ghana_water (omit for dstv/gotv/startimes). For ecg, account is the specific meter number from the /lookup meters array — not the phone.
  • →amount must be within the live min_amount/max_amount from GET /billers (defaults GHS 1.00–1000.00).
  • →Without a reference, sending the same biller + account + amount twice within 30 seconds is rejected with 409. If your first request timed out, reuse that request's original reference — you'll get the original order back via idempotent replay. A new reference does not bypass the 30-second window; genuinely distinct same-amount payments to the same account must wait it out.
  • →commission_share_percent is your cut of the platform commission (admin-configurable) — it is credited to your Commission Wallet once the order completes, not at response time.

Code Sample

cURL
# DSTV — account-only biller
curl -X POST https://api.kingflexygh.com/api/v2/utilities/pay \
  -H "Authorization: kf_cs_live_your_commission_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "biller": "dstv",
    "account": "7041234567",
    "amount": 65.00,
    "reference": "bill_dstv_7041234567_01"
  }'

# ECG — account is the METER (from lookup meters[]), phone is required too
curl -X POST https://api.kingflexygh.com/api/v2/utilities/pay \
  -H "Authorization: kf_cs_live_your_commission_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "biller": "ecg",
    "account": "3701234567",
    "phone": "0551617309",
    "amount": 50.00,
    "reference": "bill_ecg_3701234567_01"
  }'
GET/api/v2/utilities/orders/{reference}Poll the fulfillment status of a utility bill order using the reference from the /pay response. Only returns orders that belong to your own account.

Poll the fulfillment status of a utility bill order using the reference from the /pay response. Only returns orders that belong to your own account.

Response

{
  "success": true,
  "data": {
    "reference": "UTIL-DSTV-3f9a2b1c4d5e6f70",
    "status": "refunded",
    "payment_status": "paid",
    "biller": "dstv",
    "account_number": "7041234567",
    "account_name": "KWAME MENSAH",
    "amount": 65.00,
    "commission_earned": null,
    "reason": "The transaction could not be completed by the payment provider.",
    "created_at": "2026-...",
    "updated_at": "2026-..."
  }
}
  • →Status flow: pending → processing → completed | failed | refunded.
  • →The account field here is called account_number — not account as in the /pay request body. Same value, different key name across endpoints.
  • →commission_earned is null until the order reaches completed — it is your realized share of the commission, credited to your Commission Wallet at that point.
  • →A definitive provider failure auto-refunds your wallet — status becomes "refunded" and reason is present with a short, fixed explanation (never raw provider text).
  • →Poll every few seconds after /pay until status leaves pending / processing.

Code Sample

cURL
curl -X GET https://api.kingflexygh.com/api/v2/utilities/orders/UTIL-DSTV-3f9a2b1c4d5e6f70 \
  -H "Authorization: kf_cs_live_your_commission_key_here"

Rate Limits (per key)

EndpointLimit
GET /billers30 / min
GET /lookup10 / min
POST /pay6 / min
GET /orders/{reference}30 / min

Error Codes (this section)

CodeWhen it occurs
400Invalid biller/account/phone/amount/reference, or insufficient wallet balance
401Missing or invalid API key
403Wrong key type (commission key required here; standard key required everywhere else), key pending/revoked, or account suspended
404Account/meter/smartcard not found (lookup), or order not found (status)
409Duplicate order — same biller + account + amount resent within 30s without a reference
429Rate limit exceeded — see limits above
502Billing provider temporarily unreachable — retry shortly (lookup only)
503Utility bills, or this specific biller, currently disabled by an admin

10Tips & Recommendations

One key type, one purpose — a standard key covers data, results checker and AFA; a Commission Services key covers utilities and airtime; an SMS key covers SMS. A key is confined to its own section — a standard key cannot call /utilities/*, /airtime/*, or /sms/*, and vice versa.

Standard key — data, results checker, AFA

  • →Always send a unique reference per order — it becomes your idempotency key. A retry with the SAME reference and body safely returns the existing order instead of charging twice; reusing a reference for a genuinely DIFFERENT order returns 409 instead of a silent duplicate charge.
  • →Poll GET .../orders/{reference} after placing an order rather than assuming success from the initial pending status.
  • →Results Checker vouchers arrive directly in the purchase response — save them immediately. There is no separate voucher-retrieval call beyond the order-status lookup.
  • →Validate the AFA Ghana Card format and region client-side before calling the API — it avoids a wasted request on an obvious input mistake.
  • →If you serve dealer/agent accounts, check GET /account/role — pricing is expiry-aware everywhere, so a lapsed reseller is automatically billed as a customer the moment their tier expires.
  • →Every list endpoint returns at most 30 records. Design your integration to look up by reference or page through results, not to fetch everything in one call.

Commission Services key — utilities, airtime

  • →Call GET /utilities/billers and GET /utilities/lookup before POST /utilities/pay — the payment call validates against what lookup returns, so skipping it just produces avoidable 400s.
  • →This key type is scoped to /utilities/* and /airtime/* only — it cannot reach data, results checker, AFA, or SMS endpoints.

SMS key

  • →Check GET /sms/senders for your approved sender IDs before sending — an unapproved sender ID is rejected outright.
  • →Check GET /sms/balance before a large campaign so you don't hit a funding failure mid-send.
  • →Campaign and message list endpoints are capped at 30 records per page — page with ?page= rather than assuming one call covers a whole campaign.

Network number validation

We detect a recipient/beneficiary's network from the number's prefix before submitting an order. As of this writing:

NetworkPrefixes
MTN024, 025, 053, 054, 055, 059
Telecel020, 050
AirtelTigo026, 027, 056, 057

These are not guaranteed to stay fixed — Ghanaian operators occasionally get reassigned or new ranges opened by the regulator. Don't hardcode this list as a permanent source of truth in your own client-side validation; our API's response is the final word on whether a number/network pairing is accepted, and it's worth re-checking this page periodically for changes.

Need a higher rate limit, custom pricing, or a role adjustment? Message admin support from your dashboard — don't build workarounds around a limit; we can usually just raise it for you.

11Supported Networks

Network ValueProviderNotes
"MTN"MTN GhanaMost widely available bundles
"Telecel"Telecel Ghana (formerly Vodafone)
"AT-iShare"AirtelTigo iShareAirtelTigo bundle type 1
"AT-BigTime"AirtelTigo BigTimeAirtelTigo bundle type 2
Network values are case-sensitive. Use GET /packages to see exactly which networks and sizes are currently available.

This is the complete list — the four networks above are the only ones this API serves. There is no network value for any carrier outside Ghana, and none will be accepted.

12Error Codes

CodeWhen it occurs
400Bad request — invalid phone, volume_gb, network value, or malformed body
401Missing or invalid API key
403Key pending approval, revoked, suspended account, or role not allowed
404Package or order not found for the given network/size/reference
409Duplicate reference — an order with this reference already exists. On /data/purchase specifically, an MTN recipient not yet whitelisted with our supplier also returns 409 (see that endpoint's notes) — /data/bulk skips those orders individually instead of returning an error.
429Rate limit exceeded — back off and retry after a short delay
500Internal server error — contact support if persistent
503API feature temporarily disabled by administrator

13Full Examples

Complete runnable data purchase example. Select your language.

cURL
curl -X POST https://api.kingflexygh.com/api/v2/data/purchase \
  -H "Authorization: kf_live_your_api_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "network": "MTN",
    "volume_gb": 5,
    "recipient": "0551617309",
    "reference": "order_001"
  }'

Ready to start building?

© 2026 KiNG FLEXY TECHNOLOGIES LTD · Need help? Contact support via your dashboard.