Skip to main content

Setup your environment

Learn how to update your docs locally and deploy them to the public.

Prerequisites

Before you begin, ensure you have:
  • A Zuba account with API access
  • Your API credentials (API key and secret)
  • Basic knowledge of REST APIs

Get your API credentials

  1. Log in to your Zuba Test Dashboard
  2. Navigate to API Settings
  3. Click Generate API Credentials
  4. Save your Client ID, Client Secret, and Token URL securely
See the Authentication Guide for detailed instructions on obtaining access tokens.
Never expose your Client Secret in client-side code or public repositories. Always keep it secure on your server.

Rate Limits

The API enforces rate limits to ensure fair usage and platform stability:
LimitRequestsWindow
Burst10per second
Sustained100per minute
Hourly1,000per hour
If you exceed these limits, you’ll receive a 429 Too Many Requests response. Implement exponential backoff in your integration to handle rate limiting gracefully.

Create your first beneficiary

Before sending payouts, you need to create a beneficiary with their banking details:
curl -X POST "https://api.sandbox.zuba.com/v1/beneficiaries" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "John Doe",
    "email": "john.doe@example.com",
    "country": "US",
    "countrySubdivision": "NY",
    "address": "123 Main St",
    "city": "New York",
    "postcode": "10001",
    "accounts": [{
      "type": "bank_account",
      "currency": "USD",
      "data": {
        "accountNumber": "1234567890",
        "routingNumber": "021000021",
        "accountHolderName": "John Doe",
        "bankName": "Chase Bank"
      }
    }]
  }'
const beneficiary = await fetch('https://api.sandbox.zuba.com/v1/beneficiaries', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    name: 'John Doe',
    email: 'john.doe@example.com',
    country: 'US',
    countrySubdivision: 'NY',
    address: '123 Main St',
    city: 'New York',
    postcode: '10001',
    accounts: [{
      type: 'bank_account',
      currency: 'USD',
      data: {
        accountNumber: '1234567890',
        routingNumber: '021000021',
        accountHolderName: 'John Doe',
        bankName: 'Chase Bank'
      }
    }]
  })
});

const beneficiaryData = await beneficiary.json();
console.log(beneficiaryData);
import requests

beneficiary = requests.post(
    'https://api.sandbox.zuba.com/v1/beneficiaries',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'Content-Type': 'application/json'
    },
    json={
        'name': 'John Doe',
        'email': 'john.doe@example.com',
        'country': 'US',
        'countrySubdivision': 'NY',
        'address': '123 Main St',
        'city': 'New York',
        'postcode': '10001',
        'accounts': [{
            'type': 'bank_account',
            'currency': 'USD',
            'data': {
                'accountNumber': '1234567890',
                'routingNumber': '021000021',
                'accountHolderName': 'John Doe',
                'bankName': 'Chase Bank'
            }
        }]
    }
)

beneficiary_data = beneficiary.json()
print(beneficiary_data)
import java.net.http.*;
import java.net.URI;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;

HttpClient client = HttpClient.newHttpClient();

JsonObject accountData = new JsonObject();
accountData.addProperty("accountNumber", "1234567890");
accountData.addProperty("routingNumber", "021000021");
accountData.addProperty("accountHolderName", "John Doe");
accountData.addProperty("bankName", "Chase Bank");

JsonObject account = new JsonObject();
account.addProperty("type", "bank_account");
account.addProperty("currency", "USD");
account.add("data", accountData);

JsonArray accounts = new JsonArray();
accounts.add(account);

JsonObject requestBody = new JsonObject();
requestBody.addProperty("name", "John Doe");
requestBody.addProperty("email", "john.doe@example.com");
requestBody.addProperty("country", "US");
requestBody.addProperty("countrySubdivision", "NY");
requestBody.addProperty("address", "123 Main St");
requestBody.addProperty("city", "New York");
requestBody.addProperty("postcode", "10001");
requestBody.add("accounts", accounts);

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.sandbox.zuba.com/v1/beneficiaries"))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(new Gson().toJson(requestBody)))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

JsonObject beneficiaryData = new Gson().fromJson(response.body(), JsonObject.class);
System.out.println(beneficiaryData);

Check your account balance

Before sending payouts, ensure your account has sufficient funds. You can check your balance across all currencies:
curl -X GET "https://api.sandbox.zuba.com/v1/ledger/balances" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
const balances = await fetch('https://api.sandbox.zuba.com/v1/ledger/balances', {
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
  }
});

const balanceData = await balances.json();
console.log(balanceData);
import requests

balances = requests.get(
    'https://api.sandbox.zuba.com/v1/ledger/balances',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
    }
)

balance_data = balances.json()
print(balance_data)
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.sandbox.zuba.com/v1/ledger/balances"))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .GET()
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

JsonObject balanceData = new Gson().fromJson(response.body(), JsonObject.class);
System.out.println(balanceData);
If your account has zero balance, payouts will fail. Contact your account manager or use the dashboard to fund your account before proceeding.

Send your first payout

Now you can send a payout to your beneficiary. RECOMMENDED: Reference the beneficiary by ID (from the previous step). Note that amount is passed as a string to avoid floating-point precision issues. Currency Fields: inputCurrency is the currency from your account you’ll be paying from, while currency is what the beneficiary will receive (automatic conversion if different): Sender Types: senderInfo.type is 'individual' (default when omitted) for natural-person senders, or 'business' for legal entities. The examples below use an individual sender; for a business sender, see Business sender example.
curl -X POST "https://api.sandbox.zuba.com/v1/payouts" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientRef": "PAYOUT-INV-001",
    "amount": "1000.00",
    "inputCurrency": "EUR",
    "currency": "NGN",
    "route": "bank_transfer",
    "senderInfo": {
      "firstName": "Jack",
      "lastName": "Jones",
      "address": "456 London Road",
      "city": "London",
      "postalCode": "SW1A 1AA",
      "country": "GB",
      "dateOfBirth": "1985-06-15"
    },
    "beneficiary": {
      "id": "BENEFICIARY_ID_FROM_PREVIOUS_STEP"
    },
    "reference": "Invoice #INV-001",
    "description": "Payment for marketing services"
  }'
const payout = await fetch('https://api.sandbox.zuba.com/v1/payouts', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    clientRef: 'PAYOUT-INV-001',
    amount: '1000.00',
    inputCurrency: 'EUR',
    currency: 'NGN',
    senderInfo: {
      firstName: 'Jack',
      lastName: 'Jones',
      address: '456 London Road',
      city: 'London',
      postalCode: 'SW1A 1AA',
      country: 'GB',
      dateOfBirth: '1985-06-15'
    },
    route: 'bank_transfer',
    beneficiary: {
      id: beneficiaryData.id
    },
    reference: 'Invoice #INV-001',
    description: 'Payment for marketing services'
  })
});

const payoutData = await payout.json();
console.log(payoutData);
import requests

payout = requests.post(
    'https://api.sandbox.zuba.com/v1/payouts',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'Content-Type': 'application/json'
    },
    json={
        'clientRef': 'PAYOUT-INV-001',
        'amount': '1000.00',
        'inputCurrency': 'EUR',
				'senderInfo': {
					'firstName': 'Jack',
					'lastName': 'Jones',
					'address': '456 London Road',
					'city': 'London',
					'postalCode': 'SW1A 1AA',
					'country': 'GB',
					'dateOfBirth': '1985-06-15'
				},
        'currency': 'NGN',
        'route': 'bank_transfer',
        'beneficiary': {
            'id': beneficiary_data['id']
        },
        'reference': 'Invoice #INV-001',
        'description': 'Payment for marketing services'
    }
)

payout_data = payout.json()
print(payout_data)
JsonObject beneficiaryRef = new JsonObject();
beneficiaryRef.addProperty("id", beneficiaryData.get("id").getAsString());

JsonObject senderInfo = new JsonObject();
senderInfo.addProperty("firstName", "Jack");
senderInfo.addProperty("lastName", "Jones");
senderInfo.addProperty("address", "456 London Road");
senderInfo.addProperty("city", "London");
senderInfo.addProperty("postalCode", "SW1A 1AA");
senderInfo.addProperty("country", "GB");
senderInfo.addProperty("dateOfBirth", "1985-06-15");

JsonObject payoutRequest = new JsonObject();
payoutRequest.addProperty("clientRef", "PAYOUT-INV-001");
payoutRequest.addProperty("amount", "1000.00");
payoutRequest.addProperty("inputCurrency", "EUR");
payoutRequest.addProperty("currency", "NGN");
payoutRequest.addProperty("route", "bank_transfer");
payoutRequest.add("senderInfo", senderInfo);
payoutRequest.add("beneficiary", beneficiaryRef);
payoutRequest.addProperty("reference", "Invoice #INV-001");
payoutRequest.addProperty("description", "Payment for marketing services");

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.sandbox.zuba.com/v1/payouts"))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(new Gson().toJson(payoutRequest)))
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

JsonObject payoutData = new Gson().fromJson(response.body(), JsonObject.class);
System.out.println(payoutData);

Business sender example

When the sender is a legal entity rather than a natural person, set senderInfo.type to 'business' and provide companyName, registrationNumber, and country. The registrationNumber is the company’s official registration identifier and is used as the AML pivot for sanctions and UBO screening. Business senders do not carry firstName, lastName, or dateOfBirth.
curl -X POST "https://api.sandbox.zuba.com/v1/payouts" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "clientRef": "PAYOUT-INV-002",
    "amount": "1000.00",
    "inputCurrency": "EUR",
    "currency": "NGN",
    "route": "bank_transfer",
    "senderInfo": {
      "type": "business",
      "companyName": "Acme Trading Ltd",
      "registrationNumber": "12345678",
      "address": "1 Finsbury Square",
      "city": "London",
      "postalCode": "EC2A 1AE",
      "country": "GB"
    },
    "beneficiary": {
      "id": "BENEFICIARY_ID_FROM_PREVIOUS_STEP"
    },
    "reference": "Invoice #INV-002",
    "description": "Payment for marketing services"
  }'
const payout = await fetch('https://api.sandbox.zuba.com/v1/payouts', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    clientRef: 'PAYOUT-INV-002',
    amount: '1000.00',
    inputCurrency: 'EUR',
    currency: 'NGN',
    route: 'bank_transfer',
    senderInfo: {
      type: 'business',
      companyName: 'Acme Trading Ltd',
      registrationNumber: '12345678',
      address: '1 Finsbury Square',
      city: 'London',
      postalCode: 'EC2A 1AE',
      country: 'GB'
    },
    beneficiary: {
      id: beneficiaryData.id
    },
    reference: 'Invoice #INV-002',
    description: 'Payment for marketing services'
  })
});
import requests

payout = requests.post(
    'https://api.sandbox.zuba.com/v1/payouts',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN',
        'Content-Type': 'application/json'
    },
    json={
        'clientRef': 'PAYOUT-INV-002',
        'amount': '1000.00',
        'inputCurrency': 'EUR',
        'currency': 'NGN',
        'route': 'bank_transfer',
        'senderInfo': {
            'type': 'business',
            'companyName': 'Acme Trading Ltd',
            'registrationNumber': '12345678',
            'address': '1 Finsbury Square',
            'city': 'London',
            'postalCode': 'EC2A 1AE',
            'country': 'GB'
        },
        'beneficiary': {
            'id': beneficiary_data['id']
        },
        'reference': 'Invoice #INV-002',
        'description': 'Payment for marketing services'
    }
)
JsonObject businessSenderInfo = new JsonObject();
businessSenderInfo.addProperty("type", "business");
businessSenderInfo.addProperty("companyName", "Acme Trading Ltd");
businessSenderInfo.addProperty("registrationNumber", "12345678");
businessSenderInfo.addProperty("address", "1 Finsbury Square");
businessSenderInfo.addProperty("city", "London");
businessSenderInfo.addProperty("postalCode", "EC2A 1AE");
businessSenderInfo.addProperty("country", "GB");

JsonObject businessPayoutRequest = new JsonObject();
businessPayoutRequest.addProperty("clientRef", "PAYOUT-INV-002");
businessPayoutRequest.addProperty("amount", "1000.00");
businessPayoutRequest.addProperty("inputCurrency", "EUR");
businessPayoutRequest.addProperty("currency", "NGN");
businessPayoutRequest.addProperty("route", "bank_transfer");
businessPayoutRequest.add("senderInfo", businessSenderInfo);
businessPayoutRequest.add("beneficiary", beneficiaryRef);
businessPayoutRequest.addProperty("reference", "Invoice #INV-002");
businessPayoutRequest.addProperty("description", "Payment for marketing services");

Track payout status

You can check the status of your payout:
curl -X GET "https://api.sandbox.zuba.com/v1/payouts/YOUR_PAYOUT_ID" \
  -H "Authorization: Bearer YOUR_ACCESS_TOKEN"
const status = await fetch(`https://api.sandbox.zuba.com/v1/payouts/${payoutData.id}`, {
  headers: {
    'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
  }
});

const statusData = await status.json();
console.log('Payout status:', statusData.status);
import requests

status = requests.get(
    f'https://api.sandbox.zuba.com/v1/payouts/{payout_data["id"]}',
    headers={
        'Authorization': 'Bearer YOUR_ACCESS_TOKEN'
    }
)

status_data = status.json()
print(f'Payout status: {status_data["status"]}')
String payoutId = payoutData.get("id").getAsString();

HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.sandbox.zuba.com/v1/payouts/" + payoutId))
    .header("Authorization", "Bearer YOUR_ACCESS_TOKEN")
    .GET()
    .build();

HttpResponse<String> response = client.send(request,
    HttpResponse.BodyHandlers.ofString());

JsonObject statusData = new Gson().fromJson(response.body(), JsonObject.class);
System.out.println("Payout status: " + statusData.get("status").getAsString());

Next Steps

Authentication

Learn about secure authentication methods

Webhooks

Set up real-time payment notifications

Batch Payouts

Process multiple payments efficiently

API Reference

Explore the complete API documentation