API reference
Wallets
A wallet holds one asset for one user. Every user has at most one wallet per asset.
List a user's wallets
GET/v1/users/{user_id}/wallets
Returns a page of Wallet objects.
Path parameters
user_idstringrequiredStarts with
usr_.
Query parameters
limitintegerDefault
10.starting_afterstringCursor; an object ID. Returns the page after it. Cannot be combined with
ending_before.ending_beforestringCursor; an object ID. Returns the page before it. Cannot be combined with
starting_after.assetstringA wallet asset code. The set is data on
GET /routes. In 1.0 it holds two assets:ndeipi-points: Ndeipi Points, bought with fiat on Absa or PayPal at a fixed price per currency and cashed out the same way. Every user's default asset.ndeipi-coin: NdeipiCoin, opt-in. Its price moves. It is bought and sold only by converting points at a locked quote (POST /quotes), never directly with fiat. A wallet needsacknowledge_price_risk: trueto create.
Responses
- 200A page of wallets.
- 401The API key is missing, invalid or revoked.
- 404The object does not exist or belongs to another integrator.
- 429The key is over its rate limit.
- 5XXServer error. Safe to retry with the same idempotency key.
curl "https://sandbox.api.ndeipi.example/v1/users/usr_01JA8Z2F5G6H7J8K9M0N1P2Q3R/wallets" \
-H "Api-Key: $NDEIPI_API_KEY"{
"data": [
{
"id": "wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS",
"object": "wallet",
"user_id": "usr_01JA8Z2F5G6H7J8K9M0N1P2Q3R",
"asset": "ndeipi-points",
"decimals": 2,
"status": "active",
"balance": {
"object": "wallet_balance",
"wallet_id": "wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS",
"asset": "ndeipi-points",
"available": "75.00",
"pending": "0.00",
"cashable": "60.00",
"as_of": "2026-10-16T09:30:02Z"
},
"price_risk_acknowledged_at": null,
"metadata": {},
"version": 1,
"created_at": "2026-10-16T09:30:00Z"
}
],
"has_more": false
}Create a wallet
POST/v1/users/{user_id}/wallets
Creates a wallet for an approved user. A user holds at most one wallet per asset in 1.0; a second create for the same asset returns 409 wallet_exists. That wallet is the user's default for the asset, which transfers.send resolves.
Returns Wallet.
Path parameters
user_idstringrequiredStarts with
usr_.
Headers
Idempotency-KeyheaderrequiredA unique key for this write, up to 255 characters. Send the same key to retry safely; see idempotency.
Body
assetstringrequiredA wallet asset code. The set is data on
GET /routes. In 1.0 it holds two assets:ndeipi-points: Ndeipi Points, bought with fiat on Absa or PayPal at a fixed price per currency and cashed out the same way. Every user's default asset.ndeipi-coin: NdeipiCoin, opt-in. Its price moves. It is bought and sold only by converting points at a locked quote (POST /quotes), never directly with fiat. A wallet needsacknowledge_price_risk: trueto create.
acknowledge_price_riskbooleanRequired and
trueforndeipi-coin: the integrator confirms the user has been shown that NdeipiCoin's price moves and a balance can fall in value. Without it the create returns422 price_risk_not_acknowledged. The time of acknowledgement is recorded on the wallet.metadataobjectIntegrator key-value data, returned unchanged. Up to 50 keys; keys up to 40 characters, values up to 500.
Responses
- 201Wallet created.
- 400The request is malformed.
- 401The API key is missing, invalid or revoked.
- 403The key may not perform this action, or the user is not approved.
- 404The object does not exist or belongs to another integrator.
- 409The request conflicts with the object's current state or an earlier request.
- 422The request is well formed but fails validation or a business rule.
- 429The key is over its rate limit.
- 5XXServer error. Safe to retry with the same idempotency key.
curl -X POST "https://sandbox.api.ndeipi.example/v1/users/usr_01JA8Z2F5G6H7J8K9M0N1P2Q3R/wallets" \
-H "Api-Key: $NDEIPI_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"asset": "ndeipi-points"
}'{
"id": "wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS",
"object": "wallet",
"user_id": "usr_01JA8Z2F5G6H7J8K9M0N1P2Q3R",
"asset": "ndeipi-points",
"decimals": 2,
"status": "active",
"balance": {
"object": "wallet_balance",
"wallet_id": "wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS",
"asset": "ndeipi-points",
"available": "0.00",
"pending": "0.00",
"cashable": "0.00",
"as_of": "2026-10-16T09:30:02Z"
},
"price_risk_acknowledged_at": null,
"metadata": {},
"version": 1,
"created_at": "2026-10-16T09:30:00Z"
}Get a wallet
GET/v1/users/{user_id}/wallets/{wallet_id}
Returns Wallet.
Path parameters
user_idstringrequiredStarts with
usr_.wallet_idstringrequiredStarts with
wal_.
Responses
- 200The wallet, with its current balance.
- 401The API key is missing, invalid or revoked.
- 404The object does not exist or belongs to another integrator.
- 429The key is over its rate limit.
- 5XXServer error. Safe to retry with the same idempotency key.
curl "https://sandbox.api.ndeipi.example/v1/users/usr_01JA8Z2F5G6H7J8K9M0N1P2Q3R/wallets/wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS" \
-H "Api-Key: $NDEIPI_API_KEY"{
"id": "wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS",
"object": "wallet",
"user_id": "usr_01JA8Z2F5G6H7J8K9M0N1P2Q3R",
"asset": "ndeipi-points",
"decimals": 2,
"status": "active",
"balance": {
"object": "wallet_balance",
"wallet_id": "wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS",
"asset": "ndeipi-points",
"available": "75.00",
"pending": "0.00",
"cashable": "60.00",
"as_of": "2026-10-16T09:30:02Z"
},
"price_risk_acknowledged_at": null,
"metadata": {},
"version": 1,
"created_at": "2026-10-16T09:30:00Z"
}Get a wallet's balance
GET/v1/users/{user_id}/wallets/{wallet_id}/balance
Returns WalletBalance.
Path parameters
user_idstringrequiredStarts with
usr_.wallet_idstringrequiredStarts with
wal_.
Responses
- 200Available and pending balances.
- 401The API key is missing, invalid or revoked.
- 404The object does not exist or belongs to another integrator.
- 429The key is over its rate limit.
- 5XXServer error. Safe to retry with the same idempotency key.
curl "https://sandbox.api.ndeipi.example/v1/users/usr_01JA8Z2F5G6H7J8K9M0N1P2Q3R/wallets/wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS/balance" \
-H "Api-Key: $NDEIPI_API_KEY"{
"object": "wallet_balance",
"wallet_id": "wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS",
"asset": "ndeipi-points",
"available": "75.00",
"pending": "0.00",
"cashable": "60.00",
"as_of": "2026-10-16T09:30:02Z"
}List a wallet's history
GET/v1/users/{user_id}/wallets/{wallet_id}/history
One entry per ledger posting line that touched the wallet. Summing amount (credits positive, debits negative) over all entries for a bucket gives that bucket's balance.
Returns a page of WalletHistoryEntry objects.
Path parameters
user_idstringrequiredStarts with
usr_.wallet_idstringrequiredStarts with
wal_.
Query parameters
limitintegerDefault
10.starting_afterstringCursor; an object ID. Returns the page after it. Cannot be combined with
ending_before.ending_beforestringCursor; an object ID. Returns the page before it. Cannot be combined with
starting_after.created_aftertimestampcreated_beforetimestamp
Responses
- 200A page of history entries.
- 401The API key is missing, invalid or revoked.
- 404The object does not exist or belongs to another integrator.
- 429The key is over its rate limit.
- 5XXServer error. Safe to retry with the same idempotency key.
curl "https://sandbox.api.ndeipi.example/v1/users/usr_01JA8Z2F5G6H7J8K9M0N1P2Q3R/wallets/wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS/history?limit=50" \
-H "Api-Key: $NDEIPI_API_KEY"{
"data": [
{
"id": "whe_01JA8ZM5AW6Y1H4F2E9D8C7B6A",
"object": "wallet_history_entry",
"wallet_id": "wal_01JA8Z4K2V9QW3H6Y7XKD2M0RS",
"transfer_id": "trf_01JA8ZC4QK7N2Y5W3V0T9S8R6P",
"bucket": "available",
"amount": "-25.00",
"balance_after": "60.00",
"description": "Transfer to usr_01JA8Z3H6J7K8M9N0P1Q2R3S4T",
"created_at": "2026-10-16T09:30:02Z"
}
],
"has_more": false
}