Danmalama API
Get your API key →
Danmalama API v1

Build on Danmalama

The Danmalama API lets you sell airtime, data, electricity, and cable TV subscriptions directly from your own platform, using the same wallet, pricing, and provider connections that power the Danmalama app. Every endpoint below is documented against the live, production API — not a simplified or hypothetical version of it.

Base URL

https://api.danmalama.com.ng/api

This API is account-based: you integrate as a Danmalama user, using your own wallet balance to fund purchases you make on behalf of your customers. There is no separate "merchant" account type — any Danmalama account can generate an API key and start integrating immediately.

Authentication

Every request is authenticated with an API key, sent in the X-API-Key header.

Getting a key

API keys are generated from inside the Danmalama app, not through this API — open the app, go to Settings → API Access, and tap Enable. The raw key is shown exactly once. If you lose it, generate a new one (this immediately invalidates the old one — there's no overlap period), or disable API access entirely from the same screen.

X-API-Key: dmk_live_3f9a1b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e

Keys are prefixed dmk_live_ followed by 48 hex characters (57 characters total). Danmalama stores only a one-way hash of your key — support cannot look up or recover a lost key for you, and neither can you retrieve it again from the app after the first time it's shown.

⚠ An API key has full account access

There is currently no way to scope a key to "purchases only." A key authenticates as your full Danmalama account — the same as being logged into the app — and can call any endpoint your account can reach, including managing your own API access, changing your PIN, and generating a wallet funding account. Treat it exactly like a password: never embed it in a mobile app, browser extension, or any client your end users can inspect. Keep it server-side only, in your own backend.

Requests & Responses

Send request bodies as JSON with Content-Type: application/json. Every response, success or failure, is wrapped in the same envelope.

Success

{
  "success": true,
  "data": { ... }
}

Error

{
  "success": false,
  "error": {
    "code": "INSUFFICIENT_BALANCE",
    "message": "Insufficient wallet balance.",
    "details": null
  }
}

error.details is present only for some errors — most carry just a code and a human-readable message. See Errors for the one case where details has a fixed, parseable shape.

Errors

Every error uses one of these codes. The HTTP status is always derived from the code — never inspect the status alone without checking error.code, since 400 covers three distinct codes.

CodeStatusMeaning
VALIDATION_ERROR400Request body failed validation, or a business rule rejected it (e.g. amount below minimum).
INSUFFICIENT_BALANCE400Your wallet balance is lower than the purchase amount.
UNAUTHORIZED401Missing or invalid X-API-Key.
FORBIDDEN403Your account is frozen, or you don't own the resource you're trying to access.
NOT_FOUND404The resource (transaction, voucher, route) doesn't exist.
CONFLICT409The request conflicts with existing state — a duplicate in-flight purchase, a voucher you already redeemed, a transaction already refunded.
RATE_LIMITED429Reserved for account-level limits (see Rate Limits for how the general per-IP limit differs).
PIN_LOCKED429Too many failed transaction PIN attempts — temporarily locked.
PROVIDER_ERROR502The upstream network/disco/cable provider declined or errored. Your wallet is automatically refunded before this is returned.
INTERNAL_ERROR500Unexpected server error. Safe to retry.
A 200 response isn't always final

A purchase can return 200 with the transaction's status field set to processing rather than successful — this happens when the upstream provider doesn't respond in time, not when it declines. Your wallet is still debited. Poll Get a transaction until the status resolves to successful, failed, or refunded. A prompt decline is never a 200 — it comes back as PROVIDER_ERROR with the debit already reversed.

Validation error details

When a request body fails schema validation (missing field, wrong type, out-of-range value), error.details has this specific shape:

{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Invalid request",
    "details": {
      "formErrors": [],
      "fieldErrors": {
        "phone": ["Enter an 11-digit phone number starting with 0"],
        "amount": ["Number must be greater than 0"]
      }
    }
  }
}

Rate Limits

Two limits apply, tracked separately:

General requests — 120 / minute Purchases & sensitive actions — 15 / minute

The stricter 15/minute limit applies to every purchase endpoint (airtime, data, electricity, cable), meter/smartcard validation, refund requests, and every voucher endpoint. Everything else (listing plans, discos, providers, your account details, transaction history) uses the general 120/minute limit.

The 429 response is not JSON

Unlike every other error on this API, a rate-limit rejection is a plain text body — Too many requests, please try again later. — not the {success,error} envelope. Detect it by status code, not by parsing the body as JSON. Standard rate-limit headers are included on every response:

RateLimit-Limit: 120
RateLimit-Policy: 120;w=60
RateLimit-Remaining: 0
RateLimit-Reset: 27
Retry-After: 27

GET /auth/me API key required

Returns your account details, including your current wallet and bonus balance. There is no separate "check balance" endpoint — use this one, or read the balance field returned by any purchase (see below).

curl https://api.danmalama.com.ng/api/auth/me \
  -H "X-API-Key: dmk_live_your_key_here"
const res = await fetch("https://api.danmalama.com.ng/api/auth/me", {
  headers: { "X-API-Key": process.env.DANMALAMA_API_KEY }
});
const { data } = await res.json();
console.log(data.user.walletBalance);

Response

{
  "success": true,
  "data": {
    "user": {
      "id": "68f1a2b3c4d5e6f7a8b9c0d1",
      "name": "Adiahn Danmalama",
      "email": "you@example.com",
      "phone": "08031234567",
      "avatarUrl": null,
      "walletBalance": 15230,
      "bonusBalance": 0,
      "gafiaBankName": "Wema Bank",
      "gafiaAccountNumber": "8123456789",
      "role": "customer",
      "hasPin": true,
      "profileComplete": true,
      "referralCode": "DAN-4F2A",
      "referralEarnings": 350,
      "createdAt": "2026-01-14T09:22:11.000Z"
    }
  }
}

Airtime

Direct top-ups for MTN, Airtel, Glo, and 9mobile.

POST /vending/airtime API key required

Buys airtime and credits it directly to the recipient's phone number.

FieldTypeDescription
networkstringrequiredOne of MTN, AIRTEL, GLO, 9MOBILE.
phonestringrequired11-digit Nigerian number starting with 0, e.g. 08031234567.
amountintegerrequiredNaira amount, whole number, greater than 0.
pinstringrequiredYour account's 4-digit transaction PIN.
bypassNetworkCheckbooleanoptionalDefault false. The API rejects a number whose prefix doesn't match the given network (likely the wrong network selected) unless this is true — useful for genuinely ported numbers.
Hourly cap

Airtime purchases are capped at ₦5,000 per hour per account, summed across successful purchases in the trailing 60 minutes. Exceeding it returns VALIDATION_ERROR with the remaining amount in the message.

curl -X POST https://api.danmalama.com.ng/api/vending/airtime \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "network": "MTN",
    "phone": "08031234567",
    "amount": 500,
    "pin": "1234"
  }'
const res = await fetch("https://api.danmalama.com.ng/api/vending/airtime", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.DANMALAMA_API_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    network: "MTN",
    phone: "08031234567",
    amount: 500,
    pin: "1234"
  })
});
const { data } = await res.json();

Response

{
  "success": true,
  "data": {
    "transaction": {
      "_id": "68f9a1b2c3d4e5f6a7b8c9d0",
      "reference": "AIRTIME-3F9A1B2C4D5E",
      "type": "airtime",
      "provider": "MTN",
      "phone": "08031234567",
      "amount": 500,
      "walletDeducted": 500,
      "bonusDeducted": 0,
      "status": "successful",
      "verificationAttempts": 0,
      "createdAt": "2026-09-30T10:12:03.000Z",
      "updatedAt": "2026-09-30T10:12:05.000Z"
    },
    "balance": 14730
  }
}

Data

Data bundles across all four networks. Plans and prices are account-specific — always fetch the live list rather than hardcoding plan IDs.

GET /vending/data/plans API key required

Lists every data plan you can buy, with pricing already resolved for your account (including any discount you've been assigned). planId is opaque — pass it straight through to Buy data, don't parse it.

curl https://api.danmalama.com.ng/api/vending/data/plans \
  -H "X-API-Key: dmk_live_your_key_here"

Response

{
  "success": true,
  "data": [
    { "planId": "173", "network": "MTN", "label": "1GB - 30 Days", "price": 550 },
    { "planId": "174", "network": "MTN", "label": "2GB - 30 Days", "price": 900 },
    { "planId": "410", "network": "AIRTEL", "label": "5GB Weekly Plan - 7 Days", "price": 1650 }
  ]
}
POST /vending/data API key required

Buys a data plan and delivers it to the recipient's phone number.

FieldTypeDescription
networkstringrequiredOne of MTN, AIRTEL, GLO, 9MOBILE — must match the plan's network.
phonestringrequired11-digit Nigerian number starting with 0.
planIdstringrequiredFrom List data plans.
pinstringrequiredYour account's 4-digit transaction PIN.
bypassNetworkCheckbooleanoptionalDefault false. Same network/phone-prefix check as airtime.
curl -X POST https://api.danmalama.com.ng/api/vending/data \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "network": "MTN",
    "phone": "08031234567",
    "planId": "173",
    "pin": "1234"
  }'
const res = await fetch("https://api.danmalama.com.ng/api/vending/data", {
  method: "POST",
  headers: {
    "X-API-Key": process.env.DANMALAMA_API_KEY,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    network: "MTN",
    phone: "08031234567",
    planId: "173",
    pin: "1234"
  })
});
const { data } = await res.json();

Response

{
  "success": true,
  "data": {
    "transaction": {
      "_id": "68f9a1b2c3d4e5f6a7b8c9d1",
      "reference": "DATA-BD029DE81705",
      "type": "data",
      "provider": "MTN",
      "planId": "173",
      "phone": "08031234567",
      "amount": 550,
      "walletDeducted": 550,
      "bonusDeducted": 0,
      "status": "successful",
      "verificationAttempts": 0,
      "createdAt": "2026-09-30T10:14:00.000Z",
      "updatedAt": "2026-09-30T10:14:02.000Z"
    },
    "balance": 14180
  }
}

Electricity

Prepaid and postpaid electricity across every major Nigerian disco. Always validate the meter before buying — the customer's resolved name from validation is required in the purchase call.

GET /vending/electricity/discos API key required

Lists every electricity distribution company (disco) you can buy for.

curl https://api.danmalama.com.ng/api/vending/electricity/discos \
  -H "X-API-Key: dmk_live_your_key_here"

Response

{
  "success": true,
  "data": [
    { "discoId": "ikeja-electric", "name": "Ikeja Electric" },
    { "discoId": "eko-electric", "name": "Eko Electric (EKEDC)" },
    { "discoId": "abuja-electric", "name": "Abuja Electric (AEDC)" }
  ]
}

Treat discoId values as opaque and always fetched live — they're illustrative above, not a fixed contract.

POST /vending/electricity/validate-meter API key required

Resolves the customer name on a meter number before you charge anyone. This does not debit your wallet.

FieldTypeDescription
discoIdstringrequiredFrom List discos.
meterNumberstringrequired
meterTypestringrequiredprepaid or postpaid.
amountintegerrequiredThe amount you intend to purchase — some discos validate differently per amount.
curl -X POST https://api.danmalama.com.ng/api/vending/electricity/validate-meter \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "discoId": "ikeja-electric",
    "meterNumber": "04123456789",
    "meterType": "prepaid",
    "amount": 5000
  }'

Response

{
  "success": true,
  "data": {
    "customerName": "ADEBAYO O. FASHOLA",
    "address": "12 Allen Avenue, Ikeja, Lagos"
  }
}
POST /vending/electricity API key required

Buys electricity credit. customerName must be the value returned by Validate meter — don't ask your own users to type it in.

FieldTypeDescription
discoIdstringrequired
meterNumberstringrequired
meterTypestringrequiredprepaid or postpaid.
amountintegerrequiredMinimum ₦1,000.
customerNamestringrequiredFrom Validate meter's response.
pinstringrequiredYour account's 4-digit transaction PIN.
curl -X POST https://api.danmalama.com.ng/api/vending/electricity \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "discoId": "ikeja-electric",
    "meterNumber": "04123456789",
    "meterType": "prepaid",
    "amount": 5000,
    "customerName": "ADEBAYO O. FASHOLA",
    "pin": "1234"
  }'

Response

{
  "success": true,
  "data": {
    "transaction": {
      "_id": "68f9a1b2c3d4e5f6a7b8c9d2",
      "reference": "ELECTRICITY-9C1D2E3F4A5B",
      "type": "electricity",
      "provider": "ikeja-electric",
      "phone": "04123456789",
      "amount": 5000,
      "walletDeducted": 5000,
      "bonusDeducted": 0,
      "status": "successful",
      "providerResponse": { "token": "1234-5678-9012-3456-7890" },
      "verificationAttempts": 0,
      "createdAt": "2026-09-30T10:20:11.000Z",
      "updatedAt": "2026-09-30T10:20:14.000Z"
    },
    "balance": 9180
  }
}

The prepaid token (when applicable) is inside providerResponse — its exact shape depends on the disco.


Cable TV

DStv, GOtv, StarTimes, and Showmax subscriptions — new plan changes or straight renewals.

GET /vending/cable/providers API key required

Lists every cable provider and their available plans.

curl https://api.danmalama.com.ng/api/vending/cable/providers \
  -H "X-API-Key: dmk_live_your_key_here"

Response

{
  "success": true,
  "data": [
    {
      "billerId": "dstv",
      "name": "DStv",
      "plans": [
        { "itemId": "dstv-compact", "label": "DStv Compact", "amount": 19000 },
        { "itemId": "dstv-premium", "label": "DStv Premium", "amount": 44500 }
      ]
    },
    {
      "billerId": "gotv",
      "name": "GOtv",
      "plans": [
        { "itemId": "gotv-max", "label": "GOtv Max", "amount": 8500 }
      ]
    }
  ]
}
POST /vending/cable/validate-smartcard API key required

Resolves the customer name on a smartcard/IUC number. If the smartcard already has an active subscription, renewalAmount is returned too — use it for a renew purchase instead of guessing the plan price.

FieldTypeDescription
billerIdstringrequiredFrom List providers.
itemIdstringoptionalA specific plan, if known.
smartcardNumberstringrequired
curl -X POST https://api.danmalama.com.ng/api/vending/cable/validate-smartcard \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "billerId": "dstv",
    "smartcardNumber": "1234567890"
  }'

Response

{
  "success": true,
  "data": {
    "customerName": "CHIOMA N. OKEKE",
    "renewalAmount": 19000
  }
}
POST /vending/cable API key required

Buys or renews a cable subscription. There's no amount field — the price is always resolved server-side from the catalog (change) or the freshly re-validated renewal amount (renew), so a client can never supply a price.

FieldTypeDescription
billerIdstringrequired
itemIdstringoptionalRequired when subscriptionType is change.
smartcardNumberstringrequired
customerNamestringrequiredFrom Validate smartcard.
subscriptionTypestringoptionalchange (default) or renew.
pinstringrequiredYour account's 4-digit transaction PIN.
curl -X POST https://api.danmalama.com.ng/api/vending/cable \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "billerId": "dstv",
    "itemId": "dstv-compact",
    "smartcardNumber": "1234567890",
    "customerName": "CHIOMA N. OKEKE",
    "subscriptionType": "change",
    "pin": "1234"
  }'

Response

{
  "success": true,
  "data": {
    "transaction": {
      "_id": "68f9a1b2c3d4e5f6a7b8c9d3",
      "reference": "CABLE-1A2B3C4D5E6F",
      "type": "cable",
      "provider": "dstv",
      "planId": "dstv-compact",
      "phone": "1234567890",
      "amount": 19000,
      "walletDeducted": 19000,
      "bonusDeducted": 0,
      "status": "successful",
      "verificationAttempts": 0,
      "createdAt": "2026-09-30T10:25:40.000Z",
      "updatedAt": "2026-09-30T10:25:42.000Z"
    },
    "balance": 30180
  }
}

Transactions

Every purchase you make — airtime, data, electricity, cable, and voucher activity — lands here as a single unified record.

GET /vending/history API key required

Lists your transactions, newest first, capped at 500. Filtering and pagination aren't available yet — filter client-side, or fetch a single transaction by id below once you have a reference to look up.

curl https://api.danmalama.com.ng/api/vending/history \
  -H "X-API-Key: dmk_live_your_key_here"

Response

{
  "success": true,
  "data": [
    {
      "_id": "68f9a1b2c3d4e5f6a7b8c9d1",
      "reference": "DATA-BD029DE81705",
      "type": "data",
      "provider": "MTN",
      "planId": "173",
      "phone": "08031234567",
      "amount": 550,
      "status": "successful",
      "createdAt": "2026-09-30T10:14:00.000Z"
    }
  ]
}
GET /vending/history/:id API key required

Fetches one transaction by its MongoDB id (not its reference string). Use this to poll a processing purchase until it resolves.

Returns 404 NOT_FOUND both when the id doesn't exist and when it belongs to a different account — this is deliberate, so a bad request never confirms whether someone else's transaction id exists.

curl https://api.danmalama.com.ng/api/vending/history/68f9a1b2c3d4e5f6a7b8c9d1 \
  -H "X-API-Key: dmk_live_your_key_here"

Response

{
  "success": true,
  "data": {
    "_id": "68f9a1b2c3d4e5f6a7b8c9d1",
    "reference": "DATA-BD029DE81705",
    "type": "data",
    "provider": "MTN",
    "planId": "173",
    "phone": "08031234567",
    "amount": 550,
    "walletDeducted": 550,
    "bonusDeducted": 0,
    "status": "successful",
    "verificationAttempts": 0,
    "createdAt": "2026-09-30T10:14:00.000Z",
    "updatedAt": "2026-09-30T10:14:02.000Z"
  }
}
POST /vending/request-refund API key required

Flags a transaction for manual admin review. This does not refund anything itself — it's a request, reviewed by a human.

FieldTypeDescription
transactionIdstringrequired
userNotestringoptionalUp to 500 characters, explaining what went wrong.
curl -X POST https://api.danmalama.com.ng/api/vending/request-refund \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "transactionId": "68f9a1b2c3d4e5f6a7b8c9d1",
    "userNote": "Customer says data never landed on their line."
  }'

Response

{ "success": true, "data": { "ok": true } }
CodeStatusWhen
NOT_FOUND404Transaction doesn't exist.
FORBIDDEN403The transaction belongs to a different account.
CONFLICT409Already refunded.

Vouchers

Pre-paid, shareable codes redeemable for wallet credit, airtime, data, electricity, or cable — useful for gifting or batch-distributing value without handing out your API key. You pay for the full batch (amountPerRedemption × maxRedemptions) up front when you create one.

POST /vouchers API key required

Creates a voucher and debits its full cost from your wallet immediately.

FieldTypeDescription
typestringrequiredwallet, airtime, data, electricity, or cable.
providerstringrequired*Network / discoId / billerId — required for every type except wallet.
planIdstringoptionalRequired for data and cable types.
amountnumberoptionalRequired for wallet, airtime, and electricity types — ignored for data/cable, whose price comes from the plan.
maxRedemptionsintegerrequired1–1000. How many times this code can be redeemed in total.
expiresAtstringrequiredISO date, must be in the future.
messagestringoptionalUp to 200 characters, shown to whoever looks up the code.
codestringoptional4–24 chars, letters/numbers/dashes. Auto-generated (DMV-XXXXXX) if omitted.
pinstringrequiredYour account's 4-digit transaction PIN.
curl -X POST https://api.danmalama.com.ng/api/vouchers \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "data",
    "provider": "MTN",
    "planId": "173",
    "maxRedemptions": 50,
    "expiresAt": "2026-12-31T23:59:59.000Z",
    "message": "Happy Sallah from Danmalama!",
    "pin": "1234"
  }'

Response

{
  "success": true,
  "data": {
    "voucher": {
      "id": "68fa1b2c3d4e5f6a7b8c9d10",
      "code": "DMV-7K3M9Q",
      "type": "data",
      "provider": "MTN",
      "planId": "173",
      "amountPerRedemption": 550,
      "maxRedemptions": 50,
      "totalCost": 27500,
      "message": "Happy Sallah from Danmalama!",
      "expiresAt": "2026-12-31T23:59:59.000Z",
      "createdAt": "2026-09-30T10:30:00.000Z",
      "redeemedCount": 0,
      "remainingRedemptions": 50
    },
    "balance": 42500
  }
}
GET /vouchers API key required

Lists every voucher you've created, newest first.

curl https://api.danmalama.com.ng/api/vouchers \
  -H "X-API-Key: dmk_live_your_key_here"
GET /vouchers/lookup/:code API key required

Previews a voucher before redeeming it — never reveals who created it or who else has redeemed it.

curl https://api.danmalama.com.ng/api/vouchers/lookup/DMV-7K3M9Q \
  -H "X-API-Key: dmk_live_your_key_here"

Response

{
  "success": true,
  "data": {
    "code": "DMV-7K3M9Q",
    "type": "data",
    "providerLabel": "1GB - 30 Days",
    "amountPerRedemption": 550,
    "message": "Happy Sallah from Danmalama!",
    "expiresAt": "2026-12-31T23:59:59.000Z",
    "expired": false,
    "fullyRedeemed": false,
    "alreadyRedeemedByYou": false
  }
}
POST /vouchers/redeem API key required

Redeems a voucher. Behavior depends on whether you pass reference (the recipient's phone number, meter number, or smartcard number):

  • With reference: delivers immediately and returns the outcome.
  • Without it: claims your one redemption slot now, delivered later via Deliver a claimed voucher. A wallet-type voucher always delivers immediately — reference doesn't apply to it.
FieldTypeDescription
codestringrequired
referencestringoptionalPhone/meter/smartcard number to deliver to. Omit to claim now, deliver later.
meterTypestringoptionalprepaid or postpaid — required when delivering an electricity voucher.
pinstringrequiredYour account's 4-digit transaction PIN.
curl -X POST https://api.danmalama.com.ng/api/vouchers/redeem \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "code": "DMV-7K3M9Q",
    "reference": "08031234567",
    "pin": "1234"
  }'

Response

{ "success": true, "data": { "ok": true, "type": "data" } }

Deferred claim (no reference) returns { "ok": true, "type": "data", "deferred": true }. A wallet voucher returns { "ok": true, "type": "wallet", "balance": 15730 } — your new balance, since it credits you directly.

CodeStatusWhen
NOT_FOUND404Code doesn't exist.
VALIDATION_ERROR400Expired, or fully redeemed.
CONFLICT409You've already redeemed this code — one redemption per account.
PROVIDER_ERROR502Delivery failed. Your redemption slot is not consumed — retry with corrected details.
POST /vouchers/:code/use API key required

Delivers a voucher you previously claimed without a reference. No PIN needed here — you already proved intent when you claimed it.

FieldTypeDescription
referencestringrequiredPhone/meter/smartcard number to deliver to.
meterTypestringoptionalRequired for an electricity voucher.
curl -X POST https://api.danmalama.com.ng/api/vouchers/DMV-7K3M9Q/use \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "reference": "08031234567" }'

Response

{ "success": true, "data": { "ok": true, "type": "data" } }
GET /vouchers/redeemed API key required

Lists vouchers you've redeemed (as opposed to List my vouchers, which lists ones you created).

curl https://api.danmalama.com.ng/api/vouchers/redeemed \
  -H "X-API-Key: dmk_live_your_key_here"

Response

{
  "success": true,
  "data": [
    {
      "code": "DMV-7K3M9Q",
      "type": "data",
      "providerLabel": "1GB - 30 Days",
      "amountPerRedemption": 550,
      "message": "Happy Sallah from Danmalama!",
      "redeemedAt": "2026-09-30T11:02:00.000Z",
      "delivered": true
    }
  ]
}

Wallet

Fund your account balance by bank transfer.

POST /wallet/virtual-account API key required

Generates a dedicated bank account number for funding your wallet by transfer. Any transfer into it credits your wallet automatically (minus a small bank charge) — usually within a minute or two.

FieldTypeDescription
bvnstringoptional*11 digits. Only required the first time — if you already have a funding account, this returns it and ignores bvn.
curl -X POST https://api.danmalama.com.ng/api/wallet/virtual-account \
  -H "X-API-Key: dmk_live_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "bvn": "12345678901" }'

Response

{
  "success": true,
  "data": {
    "accountNumber": "8123456789",
    "bankName": "Wema Bank",
    "accountName": "DANMALAMA - ADIAHN DANMALAMA"
  }
}

Ready to integrate?

Enable API access from Settings in the Danmalama app to get your key.

Open the app →