Direct Exchange

A Direct Exchange allows you to convert funds and send them directly to an external beneficiary — without requiring a wallet balance. After accepting the quote, you receive payment instructions for the source currency. Once you deposit the funds, the payout is automatically sent to the beneficiary in the target currency.

Overview

  1. Create a Beneficiary — Register the recipient's bank details
  2. Create a DIRECT_EXCHANGE Quote — Lock in the exchange rate and fees
  3. Accept the Quote — Receive payment instructions for the source currency
  4. Send Funds — Deposit funds using the provided instructions
  5. Webhook Notification — Receive confirmation when the payout to the beneficiary completes

Direct Exchange is one of only two quote types (along with CAD deposits) that return payment instructions after acceptance. Other quote types process funds from your existing wallet balance.


Step 1: Create a Beneficiary

Register the recipient who will receive the converted funds. If you've already created the beneficiary, skip to Step 2.

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
{  "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"}

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"}

Store the id for use as beneficiary_id.

For full details, see the Beneficiaries API.


Step 2: Create a DIRECT_EXCHANGE Quote

Create a quote with quote_type: "DIRECT_EXCHANGE". The source and target currencies must be different.

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

json
{  "source_currency": "USD",  "target_currency": "NGN",  "source_amount": "500.00",  "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000",  "quote_type": "DIRECT_EXCHANGE",  "tz": "UTC",  "narration": "Direct exchange to NGN beneficiary",  "origin_reference": "DX-2026-001",  "on_behalf_of": "660e8400-e29b-41d4-a716-446655440001"}

Required Parameters

ParameterTypeDescription
source_currencystringCurrency you will deposit (e.g., "USD", "CAD", "USDC")
target_currencystringCurrency the beneficiary will receive (must differ from source)
source_amountstringAmount you will deposit (decimal string)
beneficiary_idstring (UUID)ID of the beneficiary created in Step 1
quote_typestring"DIRECT_EXCHANGE"
tzstringTimezone (IANA format)
origin_referencestringYour unique reference (max 40 chars)
on_behalf_ofstring (UUID)Customer ID

Optional Parameters

ParameterTypeDescription
narrationstringDescription for the exchange
payment_networkstringRequired for stablecoin-involved quotes (e.g., "ETH", "POLYGON")
payment_addressstringRequired for stablecoin-involved quotes

Success Response (201 Created)

json
{  "quote_id": "abc12345-e89b-12d3-a456-426614174000",  "source": {    "currency": "USD",    "amount": "500.00"  },  "target": {    "currency": "NGN",    "amount": "750000.00"  },  "exchange_rate": "1500.00",  "fees": {    "processing_fee": "5.00",    "deposit_fee": "2.50",    "payout_fee": "1.50",    "total_fees": "9.00",    "fee_currency": "USD"  },  "total_payable": "509.00",  "valid_until": "2026-03-16T15:40:53Z",  "quote_status": "CREATED",  "type": "DIRECT_EXCHANGE"}

Step 3: Accept the Quote

Accept the quote to receive payment instructions. You'll be told where to send the source currency funds.

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": "abc12345-e89b-12d3-a456-426614174000",  "transaction_id": "def67890-e21b-43d2-b456-426614174111",  "transaction_reference": "TXN-DX-12345",  "payment_details": {    "quote_id": "abc12345-e89b-12d3-a456-426614174000",    "type": "USD",    "reference": "REF-DX-56789",    "payment_instructions": "Send $509.00 USD to the account details below",    "account_number": "9876543210",    "bank_name": "Receiving Bank",    "account_name": "Sznd Trust Account",    "routing_number": "021000021"  },  "total_payable": "509.00",  "timeline": {    "created_at": "2026-03-16T15:10:53Z",    "accepted_at": "2026-03-16T15:12:30Z",    "estimated_completion": "2026-03-16T16:00:00Z"  },  "status": "AWAITING_PAYMENT"}

The payment_details field contains the instructions for sending your source currency funds. This is unique to Direct Exchange and CAD deposits.


Step 4: Send Funds

Use the payment instructions from the accept response to send the total_payable amount. The specific instructions vary based on the source currency (bank transfer, Interac, wire, etc.).

Once the system confirms receipt of your funds, the payout to the beneficiary is processed automatically.


Step 5: Webhook Notification

You'll receive a transaction webhook when the payout to the beneficiary completes:

json
{  "event_type": "transaction",  "transaction_id": "def67890-e21b-43d2-b456-426614174111",  "transaction_type": "DIRECT_EXCHANGE",  "status": "COMPLETED",  "reference": "TXN-DX-12345",  "user_id": "660e8400-e29b-41d4-a716-446655440001",  "created_at": "2026-03-16T15:10:53Z",  "timestamp": "2026-03-16T15:45:00Z",  "source_currency": "USD",  "source_amount": "500.00",  "target_currency": "NGN",  "target_amount": "750000.00",  "amount_with_fees": "509.00",  "fee": "9.00",  "fee_currency": "USD",  "exchange_rate": "1500.00",  "recipient": {    "account_number": "0123456789",    "account_name": "John Doe",    "bank_name": "Access Bank",    "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000"  }}

Status Lifecycle

Direct Exchange quotes progress through these statuses:

CREATEDAWAITING_PAYMENTPAYMENT_CONFIRMEDPROCESSING_PAYOUTCOMPLETED

You can poll the quote status at any time:

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


Example: Complete Direct Exchange 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 DIRECT_EXCHANGE 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": "USD",    "target_currency": "NGN",    "source_amount": "500.00",    "beneficiary_id": "550e8400-e29b-41d4-a716-446655440000",    "quote_type": "DIRECT_EXCHANGE",    "tz": "UTC",    "narration": "Direct exchange to NGN",    "origin_reference": "DX-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/abc12345-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 processDirectExchange(apiKey, secretKey, exchangeData) {  // Step 1: Create beneficiary (if not already created)  const beneficiary = await apiCall('POST', '/api/v1/client/beneficiaries', apiKey, secretKey, {    first_name: exchangeData.recipientFirstName,    last_name: exchangeData.recipientLastName,    email: exchangeData.recipientEmail,    phone: exchangeData.recipientPhone,    bank_name: exchangeData.bankName,    account_number: exchangeData.accountNumber,    bank_code: exchangeData.bankCode,    country_code: exchangeData.countryCode,    currency_code: exchangeData.targetCurrency  });
  // Step 2: Create DIRECT_EXCHANGE quote  const quote = await apiCall('POST', '/api/v1/client/quotes', apiKey, secretKey, {    source_currency: exchangeData.sourceCurrency,    target_currency: exchangeData.targetCurrency,    source_amount: exchangeData.amount,    beneficiary_id: beneficiary.id,    quote_type: 'DIRECT_EXCHANGE',    tz: 'UTC',    narration: exchangeData.narration,    origin_reference: exchangeData.reference,    on_behalf_of: exchangeData.customerId  });
  // Step 3: Accept the quote — receive payment instructions  const result = await apiCall('POST', `/api/v1/client/quotes/${quote.quote_id}/accept`, apiKey, secretKey);
  // Step 4: Display payment instructions to user  return {    transactionId: result.transaction_id,    paymentInstructions: result.payment_details,    totalPayable: result.total_payable,    status: result.status  };}

Best Practices

  1. No Wallet Balance Needed — Direct Exchange is ideal when you want to send converted funds without maintaining a wallet balance.
  2. Follow Payment Instructions Promptly — After accepting the quote, send funds using the provided instructions before the quote expires.
  3. Currency Compliance — Some currency corridors may require additional compliance verification.
  4. Unique Origin References — Each origin_reference must be unique to prevent duplicate exchanges.
  5. Monitor Status — Use webhooks for real-time updates, or poll GET /api/v1/client/quotes/{id} to track progress.

When to Use Direct Exchange vs Swap

ScenarioUse
Convert funds within your own walletsSwap
Send converted funds to an external beneficiaryDirect Exchange
Don't have wallet balance but need to send converted fundsDirect Exchange
Quick internal currency conversionSwap