Wallets
A wallet is a ₦-denominated account tied to a user in your system. You identify your user with a userRef, your own user ID (UUID, database ID, or any string up to 255 characters). PayKore never stores your user's personal details, only the reference you provide.
Creating a wallet
curl -X POST https://api.paykore.dev/v1/wallets \
-H "Authorization: Bearer <sk_test_YOUR_KEY_HERE>" \
-H "Content-Type: application/json" \
-d '{
"user_ref": "user_357",
"currency": "NGN",
"metadata": {"plan": "premium"}
}'
Request fields:
| Field | Required | Description |
|---|---|---|
userRef | Yes | Your user's ID. Max 255 characters. Must be unique per currency within your partner account. |
currency | Yes | Always "NGN" for now. |
metadata | No | Any JSON object. Returned as-is on every wallet response. PayKore does not read it. |
Response:
{
"data":
{
"ID":"8f47af62-b9eb-4387-827f-ca3903b64450",
"PartnerID":"fec4e29a-dc37-4857-9383-01924a61070f",
"UserRef":"user_357",
"Currency":"NGN",
"Status":"pending",
"AccountNumber":"",
"AccountName":"",
"BankCode":"",
"BankName":"",
"MFBReference":"",
"AccountStatus":"provisioning",
"Metadata":
{
"plan":"premium"
},
"CreatedAt":"2026-08-20T15:20:37.872534+01:00",
"UpdatedAt":"2026-08-20T15:20:37.872534+01:00"
}
}
TypeScript SDK:
const wallet = await paykore.wallets.create({
userRef: 'user_123',
currency: 'NGN',
metadata: { plan: 'premium' },
});
console.log(wallet.id); // "wlt_9f3kA2mXpQ"
console.log(wallet.nuban); // "0123456789" the user's bank account number
The nuban and bank_name fields give you the user's real Nigerian bank account number. Display these to your user so they can receive external transfers directly into their wallet.
Fetching a wallet and balance
curl https://api.paykore.dev/v1/wallets/8f47af62-b9eb-4387-827f-ca3903b64450 \
-H "Authorization: Bearer <sk_test_YOUR_KEY_HERE>"
The balance in the response is computed from the ledger in real time and cached for 60 seconds. For the exact balance (bypassing cache), add ?nocache=true:
curl "https://api.paykore.dev/v1/wallets/8f47af62-b9eb-4387-827f-ca3903b64450?nocache=true" \
-H "Authorization: Bearer <sk_test_YOUR_KEY_HERE>"
Use ?nocache=true sparingly, for example, immediately after a credit to confirm the balance updated. For display purposes (dashboards, transaction lists), the 60-second cache is fine and reduces load.
Wallet status
| Status | Can debit | Can credit | Description |
|---|---|---|---|
pending | No | No | Wallet just created; NUBAN being provisioned by MFB (usually under 5 seconds). |
active | Yes | Yes | Normal operating state. |
frozen | No | Yes | Outbound blocked. Can still receive funds. Used for compliance holds. |
closed | No | No | Permanent. No further operations possible. Create a new wallet if needed. |
Check status from the response status field. If a debit fails with WALLET_FROZEN or WALLET_CLOSED, check the wallet's current status before retrying.
Transaction history
curl "https://api.paykore.dev/v1/wallets/8f47af62-b9eb-4387-827f-ca3903b64450/transactions?type=p2p_transfer&from=2026-08-15T00:00:00Z&limit=20" \
-H "Authorization: Bearer <sk_test_YOUR_KEY_HERE>"
Query parameters:
| Param | Description |
|---|---|
type | Filter by type: p2p_transfer, bank_transfer, ussd_payment, qr_payment, funding |
status | Filter by status: pending, processing, completed, failed |
from | ISO 8601 start date (inclusive) |
to | ISO 8601 end date (inclusive) |
limit | Results per page (default 20, max 100) |
cursor | Cursor for next page (from previous response pagination.next_cursor) |
Response:
{
"data":
[
{
"id":"1061b0fd-6b2f-4232-9600-35fc3597ed6e",
"partner_id":"fec4e29a-dc37-4857-9383-01924a61070f",
"reference":"test-transfer-003",
"type":"p2p_transfer",
"status":"completed",
"amount":500000,
"currency":"NGN",
"source_wallet":"d516e617-df5a-4bbc-800c-c4ff19ad047c",
"dest_wallet":"25a793b6-ca5a-49d0-b74a-20731426e0eb",
"source_account":null,
"dest_account":null,
"fee_breakdown":
{
"customerFee":2500,
"merchantFee":0,
"platformFee":2500,
"mfbCost":0,
"netAmount":497500
},
"split_config":null,
"mfb_reference":"",
"psp_reference":"",
"psp_meta":null,
"idempotency_key":"test-transfer-003",
"description":"",
"metadata":{},
"failed_reason":"",
"completed_at":"2026-08-15T07:33:54.66336+01:00",
"created_at":"2026-08-15T07:33:46.475303+01:00",
"updated_at":"2026-08-15T07:33:54.66336+01:00"
},
{
"id":"93d10a16-17da-48ab-ab09-8ca70331946c",
"partner_id":"fec4e29a-dc37-4857-9383-01924a61070f",
"reference":"test-transfer-002",
"type":"p2p_transfer",
"status":"completed",
"amount":500000,
"currency":"NGN",
"source_wallet":"d516e617-df5a-4bbc-800c-c4ff19ad047c",
"dest_wallet":"25a793b6-ca5a-49d0-b74a-20731426e0eb",
"source_account":null,
"dest_account":null,
"fee_breakdown":
{
"customerFee":2500,
"merchantFee":0,
"platformFee":2500,
"mfbCost":0,
"netAmount":497500
},
"split_config":null,
"mfb_reference":"",
"psp_reference":"",
"psp_meta":null,
"idempotency_key":"test-transfer-002",
"description":"",
"metadata":{},
"failed_reason":"",
"completed_at":"2026-08-14T19:05:30.799963+01:00",
"created_at":"2026-08-14T19:05:16.9709+01:00",
"updated_at":"2026-08-14T19:05:30.799963+01:00"
},
{
"id":"26244797-4a8f-4b12-9ca3-fa2fc6fb9218",
"partner_id":"fec4e29a-dc37-4857-9383-01924a61070f",
"reference":"smoke_p2p_1785701007",
"type":"p2p_transfer",
"status":"completed",
"amount":200000,
"currency":"NGN",
"source_wallet":"d516e617-df5a-4bbc-800c-c4ff19ad047c",
"dest_wallet":"c6935d70-f090-488a-9f49-147607b2d4f7",
"source_account":null,
"dest_account":null,
"fee_breakdown":
{
"customerFee":1000,
"merchantFee":0,
"platformFee":1000,
"mfbCost":0,
"netAmount":199000
},
"split_config":null,
"mfb_reference":"",
"psp_reference":"",
"psp_meta":null,
"idempotency_key":"smoke_p2p_1785701007",
"description":"",
"metadata":{},
"failed_reason":"",
"completed_at":"2026-08-02T21:05:06.330157+01:00",
"created_at":"2026-08-02T21:04:59.530532+01:00",
"updated_at":"2026-08-02T21:05:06.330157+01:00"
}
]
}
To fetch the next page, pass the cursor:
curl "https://api.paykore.dev/v1/wallets/8f47af62-b9eb-4387-827f-ca3903b64450/transactions?cursor=cur_aB1cD2eF3g" \
-H "Authorization: Bearer <sk_test_YOUR_KEY_HERE>"
Common patterns
Create a wallet on user sign-up
The standard pattern is to create a PayKore wallet when a user registers in your system, then store the wallet ID in your database:
// In your user registration handler
async function registerUser(email: string, password: string) {
// 1. Create user in your database
const user = await db.users.create({ email, password });
// 2. Create PayKore wallet
const wallet = await paykore.wallets.create({
userRef: user.id,
currency: 'NGN',
});
// 3. Store wallet ID on the user record
await db.users.update(user.id, { paykoreWalletId: wallet.id });
return user;
}
This gives every user a wallet immediately. You look up paykoreWalletId from your own database whenever you need to debit or credit that user, no need to call GET /v1/wallets just to get the ID.
Handle duplicate userRef
If you call POST /v1/wallets for a userRef that already has a wallet in that currency, PayKore returns 409 DUPLICATE_WALLET:
{
"error":{
"code":"WALLET_EXISTS",
"message":"wallet already exists for this user_ref"
}
}
The existing_wallet_id field is included so you can fetch or store it without a separate lookup. Handle this gracefully rather than treating it as a fatal error, it commonly occurs if a user signs up twice or if your registration handler retries:
try {
const wallet = await paykore.wallets.create({ userRef: user.id, currency: 'NGN' });
return wallet;
} catch (err) {
if (err.code === 'DUPLICATE_WALLET') {
// Already exists, fetch it
return await paykore.wallets.get(err.existingWalletId);
}
throw err;
}
SDK examples
TypeScript:
import { PayKore } from '@paykore/sdk';
const paykore = new PayKore({ apiKey: process.env.PAYKORE_API_KEY });
// Create
const wallet = await paykore.wallets.create({ userRef: 'user_123', currency: 'NGN' });
// Fetch
const fetched = await paykore.wallets.get('wlt_9f3kA2mXpQ');
// Transactions
const txns = await paykore.wallets.transactions('wlt_9f3kA2mXpQ', {
type: 'p2p_transfer',
limit: 20,
});
Next steps
- P2P Transfers → Move money between wallets instantly.
- Bank Transfers → Send funds to external Nigerian bank accounts.
- Core Concepts → Understand wallet status, ledger entries, and balances.