Live API / Production Ready

Build with SaukiMart
data infrastructure.

API portal for MTN, Glo, Airtel, and 9Mobile data automation. Review the contract, test endpoints, manage API keys, monitor usage, configure webhooks, and move from sandbox to live wallet debit with confidence.

View Docs
4Networks
LiveWallet debit
TestSandbox mode
RESTAPI standard

Everything you need to integrate data purchases into your product.

From your first API call to production webhooks.

OverviewQuickstartAuthenticationPlan CatalogData PlansPlan EfficiencyPurchase DataTransactionsTest ModeOpenAPI SpecIdempotencyErrorsRetry BehaviourRegister WebhookManage WebhooksEvent ReferenceVerify SignaturesAPI Terminal

Overview

One API. Four Nigerian networks.

The SaukiMart API is a small, focused REST interface for automating data purchases across MTN, Airtel, Glo, and 9Mobile. The request format is identical across all four networks - no per-network adapters, no separate contracts.

1

Fetch the live plan catalog to get current prices and codes.

2

Submit a purchase with a phone number, a plan code, and an idempotency key.

3

On success, your wallet is debited and the data is delivered immediately.

4

Optionally configure a webhook to receive delivery events in real time.

Base URLhttps://saukimart.com
FormatJSON only
StandardREST
Rate limit90 requests per minute (default)
PaymentsPre-funded wallet - live keys debit on delivery

Quickstart

Ship your first data purchase in minutes.

Follow these four steps to go from zero to a working integration.

Step 1 - Create or sign in to your SaukiMart account

If you already use the SaukiMart app, sign in with the same phone number and PIN. If not, registration takes under a minute. Once signed in, navigate to the developer section of your dashboard to activate API access.

Step 2 - Get your API key

After activating developer access, go to the Keys tab and copy your active key. Live keys start with sm_live_ and test keys start with sm_test_. Store your key server-side - never in client-side code or public repositories.

Step 3 - Fetch the plan catalog

Call GET /api/v1/data-plans to retrieve the current list of available plans across all four networks, with your developer price applied to each one.

Step 4 - Make a purchase

Send a POST to /api/v1/purchase-data with the recipient phone number, a plan code from Step 3, and a unique idempotency key.

Quickstart code samples
Shell / cURL
# 1. Fetch available data plans
curl -X GET "https://saukimart.com/api/v1/data-plans" \
  -H "x-api-key: sm_live_XXXX_...your_key_here"

# 2. Purchase data
curl -X POST "https://saukimart.com/api/v1/purchase-data" \
  -H "Content-Type: application/json" \
  -H "x-api-key: sm_live_XXXX_...your_key_here" \
  -d '{
    "phoneNumber": "08012345678",
    "planCode": 23,
    "network": 1,
    "idempotencyKey": "your-unique-request-id"
  }'

Authentication

Send your API key with every request.

All protected endpoints require your API key in the x-api-key request header. Live keys start with sm_live_ and test keys start with sm_test_. Store your key server-side - never in client-side code or public repositories.

cURL - Authenticating Requests
$curl -X GET "https://saukimart.com/api/v1/data-plans" \
-H "x-api-key: sm_live_XXXX_...your_key_here"

Key Formats

Live key: sm_live_<prefix>_<secret> debits your wallet balance on success.
Test key: sm_test_<prefix>_<secret> returns sandbox responses only (no wallet charge or actual data delivery).

Available Scopes

read:plans - Allows fetching the data plans catalog.
write:purchases - Allows submitting data purchases.
read:transactions - Allows querying past transaction logs.

You can restrict each key to specific scopes, IP addresses, and webhook URLs from the developer dashboard. Keep your API key private. If a key is ever compromised, rotate it immediately from the dashboard.

Plan Catalog

Fetch current plans before every purchase flow.

Plan prices and availability change frequently as networks adjust their offers. Always pull the live catalog dynamically rather than hardcoding plan codes or prices in your application. Cache the response briefly in your own system if needed, but treat it as short-lived data.

GET/api/v1/data-plans
Required scope: read:plans
cURL - GET /api/v1/data-plans
$curl -X GET "https://saukimart.com/api/v1/data-plans" \
-H "x-api-key: sm_live_XXXX_...your_key_here"
Response Payload
JSON
{
  "success": true,
  "discountPercent": 8,
  "docs": {
    "purchaseEndpoint": "/api/v1/purchase-data",
    "transactionsEndpoint": "/api/v1/transactions",
    "openApiEndpoint": "/api/v1/openapi",
    "authHeader": "x-api-key: sm_live_... or sm_test_..."
  },
  "plans": [
    {
      "code": 23,
      "network": "MTN",
      "dataSize": "1GB",
      "validity": "30 days",
      "appPrice": 350,
      "developerPrice": 322
    }
  ]
}

Field Guide

FieldDescription
successboolean

Indicates if the request was successfully processed.

discountPercentnumber

Your account-level discount percentage applied to retail prices.

plans[].codenumber

The unique plan code to pass to POST /api/v1/purchase-data (e.g. 23).

plans[].networkstring

Mobile network operator (MTN, AIRTEL, GLO, or 9MOBILE).

plans[].dataSizestring

Volume of data allocated to the plan (e.g. 1GB, 750MB).

plans[].validitystring

Duration of the plan validity (e.g. 30 days, 7 days).

plans[].appPricenumber

Standard retail price shown on the public user interface.

plans[].developerPricenumber

Discounted agent price debited from your developer wallet.

Integration Tips

  • Treat plan catalog details as dynamic. Avoid hardcoding prices or codes.
  • Cache catalog responses for 5-15 minutes to reduce API latency.
  • Always verify the plan code against the live catalog before initiating a purchase.

Data Plans

Curated live catalog preview.

These rows are pulled from the public plan catalog so developers can inspect current availability before signing in. Account-specific developer pricing is confirmed inside the developer dashboard.

MTN

1 plans
1GB30 days · 1-206
₦350.00
₦332.50 preview5% after sign-in

AIRTEL

1 plans
2GB30 days · 4-302
₦700.00
₦665.00 preview5% after sign-in

GLO

1 plans
3GB30 days · 2-410
₦1,100.00
₦1,045.00 preview5% after sign-in

9Mobile

1 plans
500MB7 days · 3-118
₦200.00
₦190.00 preview5% after sign-in

Plan Efficiency

Helping your users choose the best plan.

The catalog can return daily, weekly, monthly, and promotional bundles across four networks. Keep your interface flexible - new plan types and promotional bundles are added periodically.

Price per GB

Divide developerPrice by the parsed data size to calculate cost per gigabyte and rank plans from cheapest to most expensive. This is the most useful metric for high-volume or budget-conscious users.

Validity-aware selection

For users who make regular purchases, prefer longer-validity plans that stretch their budget. For urgent or one-off needs, surface smaller daily or weekly bundles at the top of your UI.

Purchase Data

Submit a data purchase for any supported network.

Submits a purchase transaction, locks the required balance, dispatches to the delivery carrier, and debits your wallet on successful delivery. On a sandbox request, the response is identical in structure but no wallet debit or real carrier delivery occurs.

POST/api/v1/purchase-data
Required scope: write:purchases
cURL - POST /api/v1/purchase-data
$curl -X POST "https://saukimart.com/api/v1/purchase-data" \
-H "Content-Type: application/json" \
-H "x-api-key: sm_live_XXXX_...your_key_here" \
-d '{
"phoneNumber": "08012345678",
"network": 1,
"planCode": 23,
"idempotencyKey": "unique-request-uuid-here"
}'
Request Body
JSON
{
  "phoneNumber": "08012345678",
  "planCode": 23,
  "network": 1,
  "idempotencyKey": "unique-request-id-123"
}
Response Payload
JSON
{
  "success": true,
  "status": "success",
  "transactionId": "uuid",
  "idempotencyKey": "unique-request-id-123",
  "sandbox": false,
  "deducted": true,
  "data": {
    "planCode": 23,
    "network": "MTN",
    "dataSize": "1GB",
    "validity": "30 days",
    "phoneNumber": "08012345678",
    "amount": 322,
    "deliveryReference": "AMG-123456",
    "sandbox": false
  },
  "newBalance": 4328
}

Field Guide

FieldDescription
phoneNumberstringRequired

The 11-digit recipient phone number in Nigeria (e.g. 08012345678).

planCodenumberRequired

The unique plan code retrieved from the data plans catalog (e.g. 23).

idempotencyKeystringRequired

A unique key (preferably UUIDv4) generated for this purchase to prevent double-charging on network retries.

successboolean

Indicates if the request was successfully processed.

statusstring

Execution status: success, failed, or sandbox.

transactionIdstring

Unique SaukiMart ledger ID for the transaction.

sandboxboolean

true if processed in test mode (sm_test keys or test number).

deductedboolean

Indicates if your developer wallet balance was charged.

data.deliveryReferencestring

Carrier reference code returned by the telco operator.

newBalancenumber

Your remaining developer wallet balance after processing.

Integration Tips

  • Idempotency is mandatory. Always send a unique idempotencyKey. If a request times out, retry with the exact same key.
  • For sandbox testing, use the phone number 08012345678 or a test key (sm_test_...). The API will simulate a successful purchase with sandbox: true and deducted: false.

Transactions

Query your full API request history.

Use this endpoint to audit past requests, confirm carrier delivery statuses, retrieve receipts, and reconcile your ledger. Results are scoped to the authenticated API key.

GET/api/v1/transactions
Required scope: read:transactions
cURL - GET /api/v1/transactions
$curl -X GET "https://saukimart.com/api/v1/transactions" \
-H "x-api-key: sm_live_XXXX_...your_key_here"
Response Payload
JSON
{
  "success": true,
  "version": "2026-04-17",
  "transactions": [
    {
      "id": "uuid",
      "transactionId": "uuid",
      "status": "success",
      "endpoint": "/api/v1/purchase-data",
      "phoneNumber": "08012345678",
      "planCode": 23,
      "idempotencyKey": "unique-request-id-123",
      "receipt": {
        "deliveryReference": "AMG-123456"
      }
    }
  ]
}

Field Guide

FieldDescription
successboolean

Indicates if the request was successfully processed.

versionstring

The active developer API version string.

transactions[]array

List of transaction objects initiated under this key.

transactions[].statusstring

Transaction status (success, failed, pending, or sandbox).

transactions[].endpointstring

The route path processed (e.g. /api/v1/purchase-data).

transactions[].phoneNumberstring

The recipient mobile phone number.

transactions[].planCodenumber

The purchased data plan code (e.g. 23).

transactions[].idempotencyKeystring

The associated idempotency key generated by your system.

transactions[].receiptobject

Nested receipt payload containing telecommunication carrier details.

Integration Tips

  • Reconcile transactions. Run automated checks in your backend against this endpoint to verify all purchases on your system match SaukiMart ledger records.
  • Status pending/processing means carrier hand-off is incomplete. Webhooks will dispatch once resolved.

Test Mode

Test your integration safely before going live.

There are two ways to run sandbox requests: use a test key (sm_test_...) or use the sandbox phone number 08012345678 with a live key. Both methods return a full success-shaped response so your code can parse receipts, handle balances, and validate your integration without touching real funds.

Sandbox response example
{
  "success": true,
  "status": "sandbox",
  "transactionId": "uuid",
  "sandbox": true,
  "deducted": false,
  "data": {
    "planCode": 23,
    "network": "MTN",
    "phoneNumber": "08012345678",
    "deliveryReference": "SANDBOX-NO-DELIVERY"
  },
  "newBalance": 4650
}

deducted: false confirms no wallet charge occurred

delivered: false confirms no real delivery was made

status: sandbox lets you branch sandbox vs live logic

The response structure matches live receipts for parser testing

OpenAPI Specification

Download the full API specification.

Returns the complete OpenAPI 3.1 specification for the SaukiMart developer API. Import this JSON file into Postman, Insomnia, Swagger UI, or any client SDK generator to get a fully documented client automatically. This is a public endpoint - no authentication key required.

GET/api/v1/openapi
Required scope: public
cURL - GET /api/v1/openapi
$curl -X GET "https://saukimart.com/api/v1/openapi"
Response Payload
JSON
{
  "openapi": "3.1.0",
  "info": {
    "title": "SaukiMart Developer API",
    "version": "2026-04-17"
  }
}

Field Guide

FieldDescription
openapistring

The OpenAPI document specification version (e.g. 3.1.0).

infoobject

Metadata description about the API catalog.

info.titlestring

The title of the developer catalog.

info.versionstring

The documentation release version.

Integration Tips

  • Use tools like openapi-generator-cli to generate client libraries for Go, Python, Java, PHP, Node.js and more.
  • Import directly into Postman or Insomnia to quickly set up a sandbox collection.

Idempotency

Send idempotencyKey on every purchase request.

Networks are unreliable. A request may time out after being received but before a response is returned, leaving you uncertain whether the purchase went through. Generate a unique key per purchase attempt and reuse the same key if you retry the exact same request.

Request showing idempotencyKey
{
  "phoneNumber": "08012345678",
  "planCode": 23,
  "network": 1,
  "idempotencyKey": "unique-request-id-123"
}
Generate a new key for each distinct purchaseReuse the same key for exact retriesDo not reuse keys across different purchases

Errors

All errors return JSON with an actionable error code.

Client-side errors use 4xx status codes, while server-side errors use 5xx. Every error response includes a machine-readable code, a human-readable description, and optionally a details object.

Error Response Shape
JSON
{
  "success": false,
  "version": "2026-04-17",
  "requestId": "req_82a3bc9f",
  "error": {
    "code": "insufficient_balance",
    "message": "Wallet balance is too low for this purchase.",
    "details": {
      "required": 322,
      "available": 150
    }
  }
}

Error Reference Table

HTTP StatusError CodeExplanation & Recovery Strategy
400invalid_phone_number

The phoneNumber is not exactly 11 digits or has an invalid prefix. Fix formatting (e.g. 08012345678) before retrying.

400invalid_plan_code

The planCode format is invalid (must be networkId-planId). Check format before retrying.

400insufficient_balance

Your developer wallet balance is below the plan price. Fund your wallet to resume purchases.

400unsupported_field

Request payload contains callbackUrl, which is deprecated. Set webhooks via dashboard instead.

400delivery_failed

The telecom network operator rejected the data transfer. Confirm the recipient number is active.

401invalid_api_key

The x-api-key header is missing, malformed, inactive, or has been revoked. Re-verify key credentials.

403phone_verification_required

Your SaukiMart account must have verified phone credentials. Complete verification via App.

404plan_not_found

No active plan matches the given code. Fetch GET /api/v1/data-plans to refresh your cached catalog.

408timeout

Delivery carrier timed out. Inspect GET /api/v1/transactions or retry using the exact same idempotencyKey.

409balance_lock_failed

Simultaneous transaction contention. Safe to retry the request with the same idempotencyKey.

429rate_limit_exceeded

Your key exceeded its per-minute rate limit. Apply exponential backoff and retry later.

429monthly_quota_exceeded

The API key has exhausted its monthly request quota. Upgrade your key quota limit in the dashboard.

500server_error

An internal database or ledger error occurred. Retry with backoff or contact administrator.

Retry Behaviour

Retry safely without creating duplicates or missed events.

For API request retries, always reuse the same idempotencyKey on a retry of the same purchase. Apply exponential backoff and query /api/v1/transactions before creating new order records. For webhook delivery, SaukiMart will retry failed requests with exponential backoff.

Register Webhook

Receive real-time delivery events for your purchases.

Instead of polling /api/v1/transactions for updates, configure a webhook URL. SaukiMart will make an HTTP POST request to your endpoint every time a transaction status updates.

1. Register URL

Sign in, go to the Webhooks tab, select your API key, and enter your public HTTPS callback URL.

2. Define Secret

Optionally define a custom Signing Secret. This secret token will be sent with every webhook request for verification.

3. Receive Events

Your callback URL is active immediately. SaukiMart will start posting JSON payloads to it when events trigger.

Incoming Webhook Payload
JSON
{
  "event": "developer.purchase.completed",
  "transactionId": "uuid",
  "status": "success",
  "planCode": 23,
  "phoneNumber": "08012345678",
  "amount": 322
}

Manage Webhooks

Update URLs and secrets without downtime.

Webhook configuration is scoped per API key. You can update the callback URL, set or rotate the signing secret, or assign webhooks to a different environment key at any time from the dashboard. Changes take effect instantly.

HTTPS Only

Localhost or unencrypted HTTP callback URLs are rejected. Secure HTTPS connections are mandatory for receiving webhooks.

Failures & Retries

If your server returns anything other than 2xx (or times out), SaukiMart registers a failure. Verify webhook deliveries inside the Webhooks tab.

Event Reference

Webhook event types and schemas.

Event NameTrigger Condition
developer.purchase.completed

Fired when a data purchase is successfully confirmed and delivered to the recipient.

developer.purchase.failed

Fired when a purchase attempt fails due to provider errors or network rejection.

developer.purchase.sandbox

Fired when a purchase is successfully processed under a sandbox/test key.

Verify Webhooks

Secure your endpoint by validating incoming requests.

When a signing secret is configured for your webhook, SaukiMart sends it as a plain-text token in the X-SaukiMart-Webhook-Secret header. Confirm this header matches your secret exactly before trusting the request.

HTTP Header Check

Header NameDescription
X-SaukiMart-Webhook-Secret

Contains the plain-text secret token you configured in the developer dashboard settings.

X-SaukiMart-Event

The event type trigger (e.g. developer.purchase.completed).

X-SaukiMart-Version

The API catalog version matching the payload format.

Node.js Express Middleware Example
app.post('/webhook', (req, res) => {
  const secretHeader = req.headers['x-saukimart-webhook-secret'];
  
  if (secretHeader !== process.env.SAUKIMART_WEBHOOK_SECRET) {
    return res.status(401).json({ error: 'Unauthorized - invalid webhook secret token' });
  }

  const { event, transactionId, status } = req.body;
  // Process payload...
  
  res.sendStatus(200);
});

API Terminal

Run live or sandbox requests directly in your browser.

The API Terminal lets you paste a key, select an endpoint, edit the request body, and inspect the response - all without leaving the docs page. It is useful for quick validation only; do not store your live API key in the browser long term.

For sandbox testing, use 08012345678 as the recipient phone number. You will receive a complete success response with zero wallet debit and zero data delivery.
browser-api-terminal
{
  "success": true,
  "docs": {
    "purchaseEndpoint": "/api/v1/purchase-data",
    "transactionsEndpoint": "/api/v1/transactions"
  },
  "plans": [
    {
      "code": 23,
      "network": "MTN",
      "dataSize": "1GB",
      "developerPrice": 322
    }
  ]
}