Skip to content

Wallet & Keys

Your wallet holds the money that purchases draw from. Keys are the credentials that let the API spend it.


Wallet balance

GET/api/v1/wallet/manage-wallet-balance

Auth: API key or session.

curl https://api.instapaybill.com/api/v1/wallet/manage-wallet-balance \
  -H "Authorization: Bearer $IPB_LIVE_KEY" \
  -H "User-Agent: my-integration/1.0"
{
  "msg": "Wallet balance retrieved successfully",
  "data": {
    "available": 45000,
    "commission": 1250,
    "bonus": 0,
    "referral": 0,
    "pending_deficit": 0
  }
}

The response is sent with Cache-Control: no-store — do not cache it.

The four wallet buckets

Bucket Purpose
available Spendable balance. Purchases draw from here.
commission Commission earned from your own sales. Move to available to spend it.
bonus Promotional bonus. Move to available to spend it.
referral Referral earnings. Move to available to spend it.

Only available can fund a purchase. A user with ₦0 in available and ₦5,000 in commission cannot buy anything until the commission is moved.

Live vs test wallets

The key prefix decides which set of buckets you see:

Key Buckets
sk_live_… available, commission, bonus, referral
sk_test_… test_available, test_commission, test_bonus, test_referral

The response uses the same field names either way — the backend maps them.

The sandbox is different again: it reports a single flat ₦100,000 virtual balance and has no buckets at all.

pending_deficit

A non-zero pending_deficit means money was taken from available for transactions that are still being verified. It is the amount at risk.


Generate a payment reference

GET/api/v1/wallet/generate-wallet-reference

Auth: API key or session.

curl https://api.instapaybill.com/api/v1/wallet/generate-wallet-reference \
  -H "Authorization: Bearer $IPB_LIVE_KEY" \
  -H "User-Agent: my-integration/1.0"

Returns a unique reference you can attach to a top-up so the incoming payment is attributed to your account. Used by the funding flows (Paystack, Monnify, Flutterwave).


Wallet history

Method Path Access Description
GET /api/v1/wallet/ App/web Wallet ledger. Requires a type query parameter.
GET /api/v1/wallet/wallet-data App/web Wallet record
GET /api/v1/wallet/manage-wallet-stat App/web Wallet statistics
GET /api/v1/wallet/manage-wallet-stat-monthly App/web Monthly statistics
GET /api/v1/wallet/manage-wallet-stat-daily App/web Daily statistics
GET /api/v1/wallet/manage-wallet App/web Wallet user record
PUT /api/v1/wallet/manage-wallet App/web Transfer to another user. Requires amount, user, type, pin and a reCAPTCHA token.
POST /api/v1/wallet/manage-wallet-pin App/web Set a wallet PIN
PUT /api/v1/wallet/manage-wallet-pin App/web Change a wallet PIN (also sends oldPin)
DELETE /api/v1/wallet/manage-wallet-pin App/web Disable the wallet PIN
GET /api/v1/wallet/manage-card App/web Saved cards
GET /api/v1/wallet/generate-virtual-account App/web Virtual account
POST /api/v1/wallet/manage-paystack App/web Fund via Paystack (reference)
POST /api/v1/wallet/manage-monnify App/web Fund via Monnify (transactionReference)
POST /api/v1/wallet/manage-flutterwave App/web Fund via Flutterwave (flw_ref, transaction_id, amount)
PUT /api/v1/wallet/manage-commission App/web Move commission to available
PUT /api/v1/wallet/manage-bonus App/web Move bonus to available
PUT /api/v1/wallet/manage-referral App/web Move referral to available
POST /api/v1/wallet/manage-withdrawal App/web Withdraw to a bank account (amount, pin)

Wallet transfers are app/web only

Moving money between users is deliberately not exposed to the API channel. The route carries UserNonApiAuth, so an API-key request gets 403 "This service is not available for api channel". The WhatsApp agent channel blocks it too, with "Use the app or website for wallet transfers and balance moves".

Buying is the API's job; moving money between users is the app's.


API keys

Key management happens in the developer portal, not over the API. The /api/v1/keys/* routes require a session and are explicitly blocked for the API channel.

Method Path Access Description
POST /api/v1/keys/ App/web, agent Generate sk_test_ and sk_live_
GET /api/v1/keys/ App/web, agent Fetch the current keys
POST /api/v1/keys/webhook App/web, agent Set the webhook URL (webhook)
PUT /api/v1/keys/webhook App/web, agent Clear the webhook URL

The service also enforces:

ensureAllowedChannel(userAuth)  // 300 if userAuth === 'api'
ensureLiveChannel(userDomain)   // 300 if userDomain === 'test'

So even a session with a test key cannot manage production keys.

The portal endpoints

The developer portal uses its own SSO-guarded routes:

Method Path Description
GET /api/v1/sandbox/keys Sandbox key, webhook URL, delivery status and counters
POST /api/v1/sandbox/keys/regenerate Rotate the sandbox key
POST /api/v1/sandbox/keys/webhook Set the sandbox webhook URL
GET /api/v1/sandbox/live-keys Live key and webhook shown in the portal
POST /api/v1/sandbox/live-keys/regenerate Generate or rotate the live key
POST /api/v1/sandbox/live-keys/webhook Set the production webhook URL
DELETE /api/v1/sandbox/live-keys/webhook Clear the production webhook URL

All of them require the developer session cookie and the exact portal Origin header.

The portal displays only Sandbox key and Live key. Older integration test credentials remain backend compatibility fields and are not offered in the portal.

Key formats

Key Format Scope
Live sk_live_ + 24 alphanumeric chars Real wallet, real providers
Sandbox sk_test_ + 64 hex chars Simulated only, /api/v1/sandbox/*

Rotating a key is immediate and total

Regenerating invalidates the old key instantly. Any integration still using it starts getting 403 "Invalid Authentication, Unauthorized User" on the very next request. Rotate deliberately, and update every consumer of the key in the same operation.


Current user

GET/api/v1/user/

Auth: API key or session.

curl https://api.instapaybill.com/api/v1/user/ \
  -H "Authorization: Bearer $IPB_LIVE_KEY" \
  -H "User-Agent: my-integration/1.0"

Returns the identity the key belongs to:

{
  "msg": "User retrieved successfully",
  "data": {
    "email": "[email protected]",
    "firstName": "Ada",
    "lastName": "Okafor",
    "telephone": "08012345678",
    "privilege": "agent",
    "isEmailVerified": true,
    "status": true,
    "statusText": "activated"
  }
}

Use it as a startup check: if privilege is not agent or status is false, the key cannot transact.


Notifications

Method Path Access Description
GET /api/v1/notification/ API key List notifications. Supports pagination and filters.
PUT /api/v1/notification/ API key Mark all as read
POST /api/v1/notification/ API key Create a notification for the user (message)
PUT /api/v1/notification/remove-for-me API key Remove notifications for the current user
DELETE /api/v1/notification/remove-for-me API key Remove notifications for the current user

Notifications carry the outcome of your transactions, including pending purchase alerts.