SZNDSZND

Fiat Payout

The Fiat Payout flow allows you to send funds from your wallet to an external bank account. This uses the Quotes API with quote_type: "WITHDRAWAL" for same-currency payouts, or quote_type: "EXCHANGE" when the source and target currencies differ.

Overview

  1. Create a Beneficiary — Register the recipient's bank details
  2. Create a WITHDRAWAL Quote — Lock in fees and create a payout quote
  3. Accept the Quote — Execute the payout
  4. Webhook Notification — Receive confirmation when the payout completes

Step 1: Create a Beneficiary

Before initiating a payout, you need to register the recipient as a beneficiary. If you've already created the beneficiary, skip to Step 2.

For corporate / company bank accounts (GBP, EUR, USD, NGN, CAD EFT), set "recipient_type": "business" and put the company name in account_name — see Beneficiaries. Then use the returned id as beneficiary_id on the quote as usual.

Endpoint

POST /api/v1/client/beneficiaries

Authentication

http
x-api-key: <your-api-key>x-timestamp: <rfc3339-timestamp>x-signature: <hmac-sha256-signature>

Example: NGN Beneficiary

json
{  "user_id": "self",  "first_name": "John",  "last_name": "Doe",  "email": "john.doe@example.com",  "phone": "+2348012345678",  "bank_name": "Access Bank",  "account_number": "0123456789",  "bank_code": "044",  "country_code": "NG",  "currency_code": "NGN",  "recipient_type": "individual"}

Example: NGN Beneficiary (corporate)

json
{  "user_id": "self",  "recipient_type": "business",  "account_name": "Acme Nigeria Ltd",  "bank_name": "Access Bank",  "account_number": "0123456789",  "bank_code": "044",  "country_code": "NG",  "currency_code": "NGN"}

Example: USD Beneficiary (ACH)

json
{  "user_id": "self",  "first_name": "Jane",  "last_name": "Smith",  "email": "jane.smith@example.com",  "phone": "+12025551234",  "bank_name": "Chase Bank",  "account_number": "123456789",  "routing_number": "021000021",  "account_type": "Checking",  "payment_method": "ACH",  "country_code": "US",  "currency_code": "USD",  "account_name": "Jane Smith",  "recipient_type": "individual",  "address": {    "street_1": "100 Main St",    "city": "San Francisco",    "state": "CA",    "postal_code": "94105",    "country": "US"  }}

Example: USD Beneficiary (corporate ACH)

json
{  "user_id": "self",  "recipient_type": "business",  "account_name": "Acme USA Inc",  "bank_name": "Chase Bank",  "account_number": "123456789",  "routing_number": "021000021",  "account_type": "Checking",  "payment_method": "ACH",  "country_code": "US",  "currency_code": "USD",  "address": {    "street_1": "100 Main St",    "city": "San Francisco",    "state": "CA",    "postal_code": "94105",    "country": "US"  }}

Example: GBP Beneficiary (corporate)

json
{  "user_id": "self",  "recipient_type": "business",  "account_name": "Acme Trading Ltd",  "bank_name": "Barclays",  "account_number": "12345678",  "sort_code": "200000",  "country_code": "GB",  "currency_code": "GBP",  "address": {    "street_1": "1 High Street",    "city": "London",    "state": "LND",    "postal_code": "SW1A 1AA",    "country": "GB"  }}

Example: CAD Beneficiary (Interac)

CAD beneficiaries use Interac e-Transfer. Only the recipient's email is required — no bank account details needed.

For non-autodeposit recipients, security question and answer are not returned in the accept-quote response. They arrive asynchronously on a transaction webhook while the payout is still PROCESSING — see interac_payout_instruction in the Transaction Webhook docs.

json
{  "first_name": "Alex",  "last_name": "Tremblay",  "email": "alex.tremblay@example.com",  "bank_name": "Interac",  "country_code": "CA",  "currency_code": "CAD"}

Example: TZS Beneficiary (Mobile money)

Mobile money payouts use the same beneficiary and quote flow as bank payouts. List operators with GET /banks/TZ?type=momo and pass the operator code as bank_code.

json
{  "first_name": "Amina",  "last_name": "Hassan",  "email": "amina.hassan@example.com",  "phone": "255712345678",  "bank_name": "HALOTEL",  "bank_code": "HALTZA",  "country_code": "TZ",  "currency_code": "TZS"}

Then create a WITHDRAWAL or EXCHANGE quote with beneficiary_id and accept it — same as Step 2 below.

Example: LRD Beneficiary (Mobile money)

Liberia mobile money payouts use the same beneficiary and quote flow. List operators with GET /banks/LR?type=momo and pass the operator code as bank_code.

json
{  "first_name": "James",  "last_name": "Kollie",  "email": "james.kollie@example.com",  "phone": "231771234567",  "bank_name": "MTN Mobile Money",  "bank_code": "MTNLBR",  "country_code": "LR",  "currency_code": "LRD"}

Currency-Specific Requirements

CurrencyRequired Fields
NGNaccount_number, bank_code, bank_name
TZS / UGX / SLE / LRD (MoMo)bank_code (operator from GET /banks/{country}?type=momo), phone, bank_name
GHS (MoMo)bank_code (operator), phone, bank_name
GHS (Bank)account_number, bank_code, bank_name
USD (ACH)account_number, routing_number, payment_method: "ACH", account_type
USD (Wire)account_number, routing_number, bic_swift_code, payment_method: "Wire"
CADemail (Interac e-Transfer)
INRaccount_number, bank_code (11-character IFSC), account_name, email, phone. See INR payout.
OtherVaries by country — see Beneficiaries API

Mobile money payouts: Use international phone format without + (e.g. 255712345678). The API rejects traditional bank codes when a mobile money operator is required. Payout execution uses the standard quote accept flow — status progresses through PROCESSING_PAYOUT to COMPLETED via the same transaction webhook as bank payouts.

Supported mobile money operators (pass code as bank_code; see Banks API for the live list):

CountryCurrencyOperators (bank_code)Phone prefix
TZTZSTIGTZA, AIRTZA, HALTZA, VODTZA255
UGUGXMTNUGA, AIRUGA256
GHGHSMTN, VOD, AIR (MoMo); banks via ?type=banks233
SLSLEORASLE, AFRSLE232
LRLRDMTNLBR, ORALBR231

Response

json
{  "id": "550e8400-e29b-41d4-a716-446655440000",  "first_name": "John",  "last_name": "Doe",  "bank_name": "Access Bank",  "account_number": "0123456789",  "country_code": "NG",  "currency_code": "NGN",  "status": "pending",  "is_verified": false}

Store the id — you'll use it as beneficiary_id in the next step.

For full details on creating beneficiaries including address objects, validation rules, and all supported currencies, see the Beneficiaries API.

INR payout {#inr-payout}

INR payouts send rupees from an INR balance to an Indian bank account (IMPS, NEFT, or RTGS). This is a same-currency withdrawal: source_currency and target_currency are both INR.

  1. Create an INR beneficiary (currency_code: "INR", country_code: "IN") with account_number, bank_code (IFSC), account_name, email, and phone. Field rules are in Beneficiaries.
  2. Create a quote with quote_type: "WITHDRAWAL".
  3. Accept the quote. Status updates use the regular transaction webhook.
json
{  "source_currency": "INR",  "target_currency": "INR",  "source_amount": "5000.00",  "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000",  "quote_type": "WITHDRAWAL",  "tz": "UTC",  "narration": "Vendor payment",  "origin_reference": "INR-PAYOUT-2026-001"}

INR deposits are a separate UPI collection. See INR UPI deposit.


Step 2: Create a WITHDRAWAL Quote

Create a quote to lock in fees and initiate the payout.

Endpoint

POST /api/v1/client/quotes

Authentication

http
x-api-key: <your-api-key>x-timestamp: <rfc3339-timestamp>x-signature: <hmac-sha256-signature>

Request Body (Same-Currency Withdrawal)

Use quote_type: "WITHDRAWAL" when the source and target currencies are the same (e.g., NGN to NGN):

json
{  "source_currency": "NGN",  "target_currency": "NGN",  "source_amount": "50000.00",  "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000",  "quote_type": "WITHDRAWAL",  "tz": "UTC",  "narration": "Vendor payment - Invoice #1234",  "origin_reference": "PAYOUT-2026-001",  "on_behalf_of": "660e8400-e29b-41d4-a716-446655440001"}

Request Body (Cross-Currency Payout)

Use quote_type: "EXCHANGE" when the source and target currencies differ (e.g., USD to NGN). This converts funds and sends to the beneficiary in a single operation:

json
{  "source_currency": "USD",  "target_currency": "NGN",  "source_amount": "100.00",  "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000",  "quote_type": "EXCHANGE",  "tz": "UTC",  "narration": "Salary payment - March 2026",  "origin_reference": "PAYOUT-2026-002",  "on_behalf_of": "660e8400-e29b-41d4-a716-446655440001"}

Required Parameters

ParameterTypeDescription
source_currencystringCurrency to send from (e.g., "NGN", "USD")
target_currencystringCurrency to deliver (e.g., "NGN", "USD")
source_amountstringAmount to send (decimal string)
beneficiary_idstring (UUID)ID of the beneficiary created in Step 1
quote_typestring"WITHDRAWAL" (same-currency) or "EXCHANGE" (cross-currency)
tzstringTimezone (IANA format, e.g., "UTC")
origin_referencestringYour unique reference for idempotency (max 40 chars)
on_behalf_ofstring (UUID)Customer ID on whose behalf this payout is made. Must own the beneficiary_id

Optional Parameters

ParameterTypeDescription
narrationstringDescription for the payout

Sender Of Record (CAD, GBP, EUR)

For CAD, GBP, and EUR payouts, the on_behalf_of customer is the sender of record, so the payout is filed under that customer rather than under your business. This requires the customer to have completed KYC: if they have not, the quote is rejected with 422 and "customer KYC is incomplete" instead of being sent under your business identity.

Complete the customer's onboarding (see Customer onboarding), then create the quote again. If on_behalf_of is omitted, your business remains the sender.

Success Response (201 Created)

json
{  "quote_id": "123e4567-e89b-12d3-a456-426614174000",  "source": {    "currency": "NGN",    "amount": "50000.00"  },  "target": {    "currency": "NGN",    "amount": "50000.00"  },  "exchange_rate": "1.00",  "fees": {    "processing_fee": "50.00",    "deposit_fee": "0.00",    "payout_fee": "25.00",    "total_fees": "75.00",    "fee_currency": "NGN"  },  "total_payable": "50075.00",  "valid_until": "2026-03-16T15:40:53Z",  "quote_status": "CREATED",  "type": "WITHDRAWAL"}

Store the quote_id — you'll need it to accept the quote.

Quotes expire after approximately 30 minutes. Accept before the valid_until timestamp.


Step 3: Accept the Quote

Accept the quote to execute the payout. Funds will be deducted from your wallet and sent to the beneficiary.

Endpoint

POST /api/v1/client/quotes/{id}/accept

Authentication

http
x-api-key: <your-api-key>x-timestamp: <rfc3339-timestamp>x-signature: <hmac-sha256-signature>

Success Response (200 OK)

json
{  "quote_id": "123e4567-e89b-12d3-a456-426614174000",  "transaction_id": "987e6543-e21b-43d2-b456-426614174111",  "transaction_reference": "TXN-REF-56789",  "total_payable": "50075.00",  "timeline": {    "created_at": "2026-03-16T15:10:53Z",    "accepted_at": "2026-03-16T15:12:30Z",    "estimated_completion": "2026-03-16T15:45:30Z"  },  "status": "PROCESSING"}

Store the transaction_id and transaction_reference for reconciliation.


Step 4: Webhook Notification

Once the payout is processed, you'll receive a transaction webhook with the status:

json
{  "event_type": "transaction",  "transaction_id": "987e6543-e21b-43d2-b456-426614174111",  "transaction_type": "WITHDRAWAL",  "status": "COMPLETED",  "reference": "TXN-REF-56789",  "user_id": "660e8400-e29b-41d4-a716-446655440001",  "created_at": "2026-03-16T15:10:53Z",  "timestamp": "2026-03-16T15:30:00Z",  "source_currency": "NGN",  "source_amount": "50000.00",  "target_currency": "NGN",  "target_amount": "50000.00",  "amount_with_fees": "50075.00",  "fee": "75.00",  "fee_currency": "NGN",  "recipient": {    "account_number": "0123456789",    "account_name": "John Doe",    "bank_name": "Access Bank",    "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000"  }}

For full details on webhook handling and signature verification, see the Webhooks documentation.

CAD Interac (non-autodeposit)

After accept, you receive the usual PROCESSING payout flow. When Interac security credentials become available, you get an additional transaction webhook with status: "PROCESSING" and interac_payout_instruction:

json
{  "event_type": "transaction",  "transaction_type": "WITHDRAWAL",  "status": "PROCESSING",  "payment_completed": false,  "target_currency": "CAD",  "target_amount": "100.00",  "interac_payout_instruction": {    "question": "What is your reference number?",    "answer": "48291"  },  "recipient": {    "email": "alex.tremblay@example.com",    "account_name": "Alex Tremblay",    "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000"  }}

Forward the question and answer to the beneficiary so they can accept the e-Transfer. A final webhook with COMPLETED or FAILED follows when the payout settles. interac_payout_instruction is omitted on all non-CAD payouts and on CAD payouts where credentials are not required.


Verify Payout Status

You can check the payout status at any time by polling the quote:

Endpoint

GET /api/v1/client/quotes/{id}

Success Response

The response includes the current quote_status which progresses through:

CREATED → AWAITING_PAYMENT → PAYMENT_CONFIRMED → PROCESSING_PAYOUT → COMPLETED

For full details, see the Quotes API.


Example: Complete Fiat Payout Flow

cURL

Step 1: Create beneficiary

bash
curl -X POST https://api.transfaar.com/api/v1/client/beneficiaries \  -H "Content-Type: application/json" \  -H "x-api-key: your-api-key" \  -H "x-timestamp: 2026-03-16T10:30:00Z" \  -H "x-signature: your-hmac-signature" \  -d '{    "first_name": "John",    "last_name": "Doe",    "email": "john.doe@example.com",    "phone": "+2348012345678",    "bank_name": "Access Bank",    "account_number": "0123456789",    "bank_code": "044",    "country_code": "NG",    "currency_code": "NGN"  }'

Step 2: Create withdrawal quote

bash
curl -X POST https://api.transfaar.com/api/v1/client/quotes \  -H "Content-Type: application/json" \  -H "x-api-key: your-api-key" \  -H "x-timestamp: 2026-03-16T10:31:00Z" \  -H "x-signature: your-hmac-signature" \  -d '{    "source_currency": "NGN",    "target_currency": "NGN",    "source_amount": "50000.00",    "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000",    "quote_type": "WITHDRAWAL",    "tz": "UTC",    "narration": "Vendor payment",    "origin_reference": "PAYOUT-2026-001",    "on_behalf_of": "660e8400-e29b-41d4-a716-446655440001"  }'

Step 3: Accept the quote

bash
curl -X POST https://api.transfaar.com/api/v1/client/quotes/123e4567-e89b-12d3-a456-426614174000/accept \  -H "Content-Type: application/json" \  -H "x-api-key: your-api-key" \  -H "x-timestamp: 2026-03-16T10:32:00Z" \  -H "x-signature: your-hmac-signature"

JavaScript

javascript
async function processFiatPayout(apiKey, secretKey, payoutData) {  const timestamp = new Date().toISOString();
  // Step 1: Create beneficiary (if not already created)  const beneficiary = await apiCall('POST', '/api/v1/client/beneficiaries', apiKey, secretKey, {    first_name: payoutData.recipientFirstName,    last_name: payoutData.recipientLastName,    email: payoutData.recipientEmail,    phone: payoutData.recipientPhone,    bank_name: payoutData.bankName,    account_number: payoutData.accountNumber,    bank_code: payoutData.bankCode,    country_code: payoutData.countryCode,    currency_code: payoutData.currency  });
  // Step 2: Create withdrawal quote  const quote = await apiCall('POST', '/api/v1/client/quotes', apiKey, secretKey, {    source_currency: payoutData.currency,    target_currency: payoutData.currency,    source_amount: payoutData.amount,    beneficiary_id: beneficiary.id,    quote_type: 'WITHDRAWAL',    tz: 'UTC',    narration: payoutData.narration,    origin_reference: payoutData.reference,    on_behalf_of: payoutData.customerId  });
  // Step 3: Accept the quote  const result = await apiCall('POST', `/api/v1/client/quotes/${quote.quote_id}/accept`, apiKey, secretKey);
  return {    transactionId: result.transaction_id,    transactionReference: result.transaction_reference,    status: result.status  };}
async function apiCall(method, path, apiKey, secretKey, body = null) {  const timestamp = new Date().toISOString();  const bodyStr = body ? JSON.stringify(body) : '';  const signature = generateHMACSignature(bodyStr, timestamp, secretKey);
  const response = await fetch(`https://api.transfaar.com${path}`, {    method,    headers: {      'Content-Type': 'application/json',      'x-api-key': apiKey,      'x-timestamp': timestamp,      'x-signature': signature    },    ...(body && { body: bodyStr })  });
  return await response.json();}

Best Practices

  1. Create Beneficiaries Once — Beneficiaries are reusable. Create them once and store the id for future payouts.
  2. Use Unique Origin References — Each origin_reference must be unique. Duplicate references will be rejected, preventing accidental double payouts.
  3. Accept Quotes Promptly — Quotes expire after ~30 minutes. Accept before the valid_until timestamp.
  4. Handle Webhooks — Always verify payout completion via webhooks rather than relying solely on polling.
  5. Validate Balances — Ensure your wallet has sufficient balance to cover the payout amount plus fees before creating a quote.
  6. Store References — Save quote_id, transaction_id, transaction_reference, and your origin_reference for reconciliation.