Wallet Service

Manage user wallets for stored value, rewards, and payments

Overview

The Wallet Service is the system of record for user value, balance, and wallet transactions. It can be used by any channel — apps, websites, partner platforms, and internal services.

Use Cases
  • Loyalty rewards storage
  • Cashback programs
  • Prepaid balances
  • In-store redemption
Channels
  • Mobile apps
  • Websites / eCommerce
  • Partner platforms
  • In-store (via wiCode)
Key Features
  • Real-time balance
  • Auth / Finalise / Reverse
  • Full audit trail
  • Pre-integrated in-store

Wallet APIs

MethodEndpointDescription
POST/wallet/usersCreate Wallet User
GET/wallet/users/{externalUserId}/balanceGet Wallet Balance
GET/wallet/wallets/{walletId}Get Wallet Balance (by ID)
POST/wallet/users/{externalUserId}/creditCredit Wallet
POST/wallet/users/{externalUserId}/authoriseAuthorise Wallet Debit
POST/wallet/users/{externalUserId}/finalise/{authorisationId}Finalise Wallet Debit
POST/wallet/users/{externalUserId}/reverse/{authorisationId}Reverse Wallet Debit
GET/wallet/users/{externalUserId}/transactionsList Wallet Transactions

Flow 1: Direct Digital Wallet

For apps, websites, and digital channels

  1. 1Call Authorise Debit to hold funds
  2. 2Complete your checkout / order flow
  3. 3Call Finalise Debit on success
  4. 4Or call Reverse Debit if cancelled
You control the full lifecycle.

Flow 2: Redeem In-Store

Pre-integrated via Yoyo VSP

  1. 1The returned PAN value can be rendered as a wiCode for the wallet user
  2. 2Display the wiCode in your app (QR or numeric)
  3. 3The customer presents the wiCode at a participating store
  4. 4Yoyo receives the POS transaction via VSP
  5. 5Yoyo automatically calls Wallet Authorise Debit
  6. 6Yoyo automatically calls Wallet Finalise Debit (or Reverse) based on outcome
No additional integration required!

Create Wallet User

Creates a wallet user for the partner shopper reference and returns the active wallet profile

POST /wallet/users
# Create a new wallet user
curl -X POST "https://api.yoyo.co.za/wallet/users" \
  -H "accept: application/json" \
  -H "apiId: {apiId}" \
  -H "apiPassword: {apiPassword}" \
  -H "Content-Type: application/json" \
  -d '{
    "externalUserId": "partner-shopper-9f04706a",
    "mobileNumber": "+27710003000",
    "firstName": "Runtime",
    "lastName": "Check",
    "email": "runtime.check@example.com"
  }'

# Response (201 Created)
{
  "userId": 4812,
  "walletId": 9264,
  "externalUserId": "partner-shopper-9f04706a",
  "mobileNumber": "+27710003000",
  "pan": "6007851234567890",
  "balance": 0,
  "currency": "ZAR",
  "status": "ACTIVE",
  "createdAt": "2026-03-23T08:13:35.069Z"
}

# Duplicate Request (409 Conflict) - Returns existing resource
{
  "userId": 4812,
  "walletId": 9264,
  "externalUserId": "partner-shopper-9f04706a",
  ...
}

Get Wallet Balance

Reads the current wallet balance using the partner shopper reference

GET /wallet/users/{externalUserId}/balance
# Get wallet balance by external user ID
curl -X GET "https://api.yoyo.co.za/wallet/users/partner-shopper-9f04706a/balance" \
  -H "accept: application/json" \
  -H "apiId: {apiId}" \
  -H "apiPassword: {apiPassword}" \
  -H "Content-Type: application/json"

# Response (200 OK)
{
  "walletId": 9264,
  "userId": 4812,
  "availableBalance": 100000,
  "reservedBalance": 0,
  "balance": 100000,
  "currency": "ZAR",
  "status": "ACTIVE"
}

Alternatively, look up by the numeric wallet ID returned during user creation:

GET /wallet/wallets/{walletId}
# Get wallet balance by wallet ID
curl -X GET "https://api.yoyo.co.za/wallet/wallets/9264" \
  -H "accept: application/json" \
  -H "apiId: {apiId}" \
  -H "apiPassword: {apiPassword}" \
  -H "Content-Type: application/json"

# Response (200 OK)
{
  "walletId": 9264,
  "userId": 4812,
  "availableBalance": 100000,
  "reservedBalance": 0,
  "balance": 100000,
  "currency": "ZAR",
  "status": "ACTIVE"
}

Credit Wallet

Credits funds into the shopper wallet using the partner transaction reference

POST /wallet/users/{externalUserId}/credit
# Credit funds to a wallet
curl -X POST "https://api.yoyo.co.za/wallet/users/partner-shopper-9f04706a/credit" \
  -H "accept: application/json" \
  -H "apiId: {apiId}" \
  -H "apiPassword: {apiPassword}" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 5000,
    "description": "Promotional wallet credit",
    "externalTransactionRef": "PARTNER_TOPUP_1711180812000_5000"
  }'

# Response (200 OK)
{
  "transactionId": 834201,
  "walletId": 9264,
  "type": "CREDIT",
  "amount": 5000,
  "availableBalance": 105000,
  "reservedBalance": 0,
  "status": "COMPLETED"
}

# Duplicate Request (409 Conflict) - Returns existing transaction
{
  "transactionId": 834201,
  "walletId": 9264,
  ...
}

Authorise Wallet Debit

Places a hold against the wallet for checkout

Use Authorise to reserve funds before completing a transaction. This creates a reservedBalance which reduces the availableBalance. You must later call Finalise or Reverse to complete the flow.

POST /wallet/users/{externalUserId}/authorise
# Authorise a wallet debit (places a hold for checkout)
curl -X POST "https://api.yoyo.co.za/wallet/users/partner-shopper-9f04706a/authorise" \
  -H "accept: application/json" \
  -H "apiId: {apiId}" \
  -H "apiPassword: {apiPassword}" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 25000,
    "description": "Checkout reserve for order 4f5c5d5f",
    "externalTransactionRef": "ORDER_4f5c5d5f_AUTH"
  }'

# Response (200 OK)
{
  "authorisationId": 834245,
  "walletId": 9264,
  "amount": 25000,
  "currency": "ZAR",
  "availableBalance": 80000,
  "reservedBalance": 25000,
  "createdAt": "2026-03-23T08:13:35.069Z"
}

# Duplicate Request (409 Conflict) - Returns existing authorisation
{
  "authorisationId": 834245,
  "walletId": 9264,
  ...
}

Finalise Wallet Debit

Finalises an existing authorisation once checkout succeeds

Call Finalise to convert the reserved balance into a completed debit. The finalAmount is optional and can be omitted to settle the full authorised amount.

POST /wallet/users/{externalUserId}/finalise/{authorisationId}
# Finalise an authorised debit (completes the transaction)
curl -X POST "https://api.yoyo.co.za/wallet/users/partner-shopper-9f04706a/finalise/834245" \
  -H "accept: application/json" \
  -H "apiId: {apiId}" \
  -H "apiPassword: {apiPassword}" \
  -H "Content-Type: application/json" \
  -d '{
    "finalAmount": 25000
  }'

# Response (200 OK)
{
  "transactionId": 834245,
  "walletId": 9264,
  "type": "DEBIT",
  "amount": 25000,
  "availableBalance": 80000,
  "reservedBalance": 0,
  "status": "COMPLETED",
  "createdAt": "2026-03-23T08:13:42.069Z",
  "authorisationId": 834245,
  "finalAmount": 25000
}

# Note: finalAmount is optional - omit to settle the full authorised amount

Reverse Wallet Debit

Releases a reserved wallet amount when checkout fails or is cancelled

Call Reverse to release the reserved funds back to the customer's available balance. Use this when an order is cancelled or the transaction is abandoned by the merchant.

POST /wallet/users/{externalUserId}/reverse/{authorisationId}
# Reverse an authorised debit (releases the hold)
curl -X POST "https://api.yoyo.co.za/wallet/users/partner-shopper-9f04706a/reverse/834245" \
  -H "accept: application/json" \
  -H "apiId: {apiId}" \
  -H "apiPassword: {apiPassword}" \
  -H "Content-Type: application/json" \
  -d '{
    "reason": "Order cancelled by merchant"
  }'

# Response (200 OK)
{
  "transactionId": 834245,
  "walletId": 9264,
  "availableBalance": 105000,
  "reservedBalance": 0,
  "status": "REVERSED",
  "createdAt": "2026-03-23T08:14:01.069Z",
  "authorisationId": 834245,
  "reason": "Order cancelled by merchant"
}

List Wallet Transactions

Returns the wallet activity stream with pagination support

Use this endpoint to inspect credits, authorisations, captures, and reversals. Supports pagination with offset and limit query parameters.

GET /wallet/users/{externalUserId}/transactions
# List wallet transactions
curl -X GET "https://api.yoyo.co.za/wallet/users/partner-shopper-9f04706a/transactions?offset=0&limit=20" \
  -H "accept: application/json" \
  -H "apiId: {apiId}" \
  -H "apiPassword: {apiPassword}" \
  -H "Content-Type: application/json"

# Response (200 OK)
{
  "walletId": 9264,
  "transactions": [
    {
      "transactionId": 834245,
      "authorisationId": 834245,
      "type": "DEBIT",
      "amount": 25000,
      "balanceAfter": 80000,
      "description": "Checkout reserve for order 4f5c5d5f",
      "status": "COMPLETED",
      "createdAt": "2026-03-23T08:13:42.069Z"
    },
    {
      "transactionId": 834201,
      "type": "CREDIT",
      "amount": 5000,
      "balanceAfter": 105000,
      "description": "Promotional wallet credit",
      "status": "COMPLETED",
      "createdAt": "2026-03-23T08:12:10.069Z"
    }
  ],
  "totalCount": 2,
  "offset": 0,
  "hasMore": false
}

Redeem In-Store

Pre-built capability for in-store wallet redemption

How it works

Redeem In-Store provides an off-the-shelf capability for in-store wallet redemption using a wiCode. Yoyo uses the VSP service underneath and automatically stitches the redemption into the wallet authorise/finalise lifecycle — you don't need to orchestrate those calls.

  1. 1The returned PAN value can be rendered as a wiCode for the wallet user
  2. 2Display the wiCode in your app (QR or numeric)
  3. 3The customer presents the wiCode at a participating store
  4. 4Yoyo receives the POS transaction via VSP
  5. 5Yoyo automatically calls Wallet Authorise Debit
  6. 6Yoyo automatically calls Wallet Finalise Debit (or Reverse) based on outcome
Key Benefit

This is a pre-built capability built on top of the wallet service. The integrator only needs to display the PAN — Yoyo handles the entire downstream redemption flow, including wallet authorisation and finalisation.