Quote
Quotes are the core of the Transfaar API β they lock in exchange rates and fees, create transactions, and drive the payment flow. Quotes are required when you need to lock rates upfront (like currency exchanges, withdrawals, swaps, and transfers), but not all transactions require quote creation.
When quotes are required:
- WITHDRAWAL - Lock rates before sending funds to external beneficiaries
- EXCHANGE - Lock rates for currency conversion with external payout
- SWAP - Lock rates for currency conversion within your wallets
- TRANSFER - Lock rates for transfers between users
- DIRECT_EXCHANGE - Lock rates and receive payment instructions for direct currency exchange
When quotes are NOT required:
- DEPOSIT with Virtual Bank Account (VBA) - For currencies with assigned VBAs (e.g., USD, GBP, NGN), deposits happen automatically when funds arrive. No upfront quote needed.
- DEPOSIT via webhook - The system creates quotes automatically when deposit webhooks are received.
Payment Instructions: Only DIRECT_EXCHANGE and CAD deposits provide payment instructions because funds don't affect your wallet β they go directly to the external beneficiary. Other quote types (like DEPOSIT with VBA) don't require instructions since you already have an assigned account.
How Quotes Work
For Transactions Requiring Quote Creation:
- Create Quote β Lock exchange rates and fees (valid for ~30 minutes)
- Accept Quote β Create transaction (and receive payment instructions for DIRECT_EXCHANGE and CAD deposits)
- Process Payment β Follow payment instructions (DIRECT_EXCHANGE and CAD deposits only) or funds are processed automatically
- Track Status β Monitor via webhooks or status polling until completion
For Deposits with Virtual Bank Accounts:
- Funds Arrive β User sends funds to their assigned VBA
- Webhook Received β System automatically creates quote and transaction
- Wallet Credited β Funds are automatically credited to user's wallet
- Track Status β Monitor via webhooks or status polling
Key Concepts:
- Quote: A priced offer with locked exchange rates, fees, and expiration time
- Quote Type: Defines the transaction (DEPOSIT, WITHDRAWAL, EXCHANGE, SWAP, TRANSFER, DIRECT_EXCHANGE)
- Payment Method: How funds are sent/received (FIAT or CRYPTO)
- Status Lifecycle:
CREATEDβ Quote generated, awaiting acceptanceAWAITING_PAYMENT/AWAITING_DEPOSITβ Accepted, waiting for fundsPAYMENT_CONFIRMED/DEPOSIT_CONFIRMEDβ Funds receivedPROCESSING_PAYOUTβ Payout in progressCOMPLETED/EXPIRED/FAILEDβ Final states
Payment Methods
Quotes support two payment methods:
FIAT- Traditional payment methods including bank transfers, Interac, cards, and other fiat railsCRYPTO- Cryptocurrency funding/payout via supported stablecoins (USDC, USDT) on supported networks (Ethereum, Polygon, etc.)
Crypto-Funded Quotes
When using payment_method: CRYPTO, you can fund quotes with stablecoins:
- Supported tokens: USDC, USDT
- Supported networks: Ethereum, Polygon, Solana (varies by token)
- For DEPOSIT: Send stablecoin, receive fiat in your wallet
- For WITHDRAWAL: Send fiat from your wallet, receive stablecoin to external address
- For DIRECT_EXCHANGE: Send stablecoin, receive fiat to external beneficiary
The system automatically handles currency conversions and fee calculations for crypto-funded transactions.
Quick Start
For Transactions Requiring Quote Creation (WITHDRAWAL, EXCHANGE, SWAP, TRANSFER, DIRECT_EXCHANGE):
- Authenticate using API key with HMAC signature (see Authentication)
- Create a customer using
POST /api/v1/client/customers(if not exists) - Create a beneficiary using
POST /api/v1/client/beneficiaries(if required for quote type) - Create a quote using
POST /api/v1/client/quoteswithorigin_referenceandon_behalf_of - Accept the quote using
POST /api/v1/client/quotes/{id}/accept- For DIRECT_EXCHANGE and CAD deposits: You'll receive payment instructions
- For other types: Transaction is created, funds processed automatically
- Track status via webhooks or polling
GET /api/v1/client/quotes/{id}
For Deposits with Virtual Bank Accounts:
- Get VBA details - User already has an assigned virtual bank account
- Funds arrive - User sends funds to their VBA
- System processes - Quote and transaction created automatically via webhook
- Track status - Monitor via webhooks or polling
Required for Every Quote Creation:
origin_reference- Unique transaction ID (max 40 chars) for idempotencyon_behalf_of- Customer ID (must belong to your business)quote_type- Transaction type (WITHDRAWAL, EXCHANGE, SWAP, TRANSFER, DIRECT_EXCHANGE)source_currency,target_currency,source_amountpayment_method- FIAT or CRYPTO
Prerequisites for Creating a Quote
Before creating a quote, you may need to prepare certain information depending on the quote type:
Exchange Rates (Optional - For Estimation)
The Exchange Rates API (GET /api/v1/client/exchange-rates) provides an estimate of exchange rates, fees, and transaction limits before creating a quote. This is optional and not required for quote creation, but can be useful to:
- Preview expected fees and exchange rates
- Validate transaction amounts against limits
- Display estimated costs to users before quote creation
Note: Exchange rates are estimates only. Actual rates and fees are locked when you create the quote. The exchange-rates endpoint is independent from quote creation - you can create quotes directly without calling it first.
π See: Exchange Rates API for detailed documentation
Beneficiary ID (beneficiary_id)
The beneficiary_id is obtained by creating a beneficiary first using the Beneficiaries API.
Required for:
EXCHANGE- External beneficiary requiredDIRECT_EXCHANGE- External beneficiary requiredWITHDRAWAL(FIAT) - External beneficiary required
Not required for:
DEPOSIT- Funds go to your own wallet (self-beneficiary created automatically)SWAP- Conversion within your own wallets (self-beneficiary created automatically)TRANSFER- Usesuser_taginstead (see below)WITHDRAWAL(CRYPTO) - Self-beneficiary created automatically
Steps:
- Call
POST /api/v1/client/beneficiariesto create a new beneficiary with the recipient's details - Extract the
idfield from the response - Use this
idas thebeneficiary_idwhen creating your quote
Example Beneficiary Response:
{
"id": "123e4567-e89b-12d3-a456-426614174000", // β Use this as beneficiary_id in quote creation
"first_name": "John",
"last_name": "Doe",
"bank_name": "Access Bank",
...
}π See: Beneficiaries API for detailed documentation
User Tag (user_tag) - For TRANSFER Only
For TRANSFER transactions, you need the recipient's user_tag instead of a beneficiary ID. The recipient must be a registered user on the Transfaar platform and have a wallet for the target currency.
Required for:
TRANSFER- Recipient's user tag is required
Not required for:
- All other quote types
Origin Reference (origin_reference) - For Business API Users
The origin_reference serves as both a unique transaction identifier and an idempotency key for quote creation. It enables proper transaction tracking, reconciliation, and prevents duplicate quote creation.
Required for:
- All business API requests - Business clients must provide a unique
origin_referencefor every quote
Idempotency:
- If you submit a quote request with an
origin_referencethat already exists, the request will be rejected with a400 Bad Requesterror - This ensures that retrying a request (e.g., due to network issues) won't create duplicate quotes
- Use the same
origin_referenceonly when you intend to reference an existing quote
Best practices:
- Use a unique identifier from your system (e.g., order ID, transaction ID)
- Maximum 40 characters
- Must be unique per quote (duplicate references will be rejected)
- Store this reference to match webhook events and API responses
- Generate a new
origin_referencefor each new transaction intent
Example:
{
"origin_reference": "ORDER-2025-001234",
...
}On Behalf Of (on_behalf_of) - For Business API Users
The on_behalf_of field identifies the actual customer (end user) for whom the business is creating the quote.
Required for:
- All business API requests - Business clients must provide the customer's user ID
Purpose:
- Identifies the actual customer initiating the transaction
- The customer must belong to your business
- Used for proper transaction attribution and compliance
Example:
{
"on_behalf_of": "123e4567-e89b-12d3-a456-426614174000",
...
}Create Quote
Create a new quote to lock in exchange rates and fees for a currency conversion or money transfer. Quotes are valid for a limited time (typically 30 minutes) and must be accepted before expiration.
Important Notes:
- Business API users:
origin_referenceandon_behalf_ofare required for all quote requests- Beneficiary ID: Required for
EXCHANGE,DIRECT_EXCHANGE, andWITHDRAWAL(FIAT). Not required forDEPOSIT,SWAP, orTRANSFER- User Tag: Required for
TRANSFERtransactions onlySee Prerequisites above for detailed requirements.
Endpoint
POST /api/v1/client/quotes
Authentication
This endpoint requires API key authentication with HMAC signature. Include your API key and signature in the request headers:
X-API-Key: <your-api-key>
X-Signature: <hmac-signature>
X-Timestamp: <unix-timestamp>π See: Authentication for detailed HMAC signing instructions
Request Body
{
"source_currency": "USD",
"target_currency": "NGN",
"source_amount": "1000.00",
"beneficiary_id": "123e4567-e89b-12d3-a456-426614174000",
"quote_type": "EXCHANGE",
"payment_method": "FIAT",
"tz": "UTC",
"narration": "Salary payment for John Doe",
"on_behalf_of": "123e4567-e89b-12d3-a456-426614174000"
}Required Parameters
| Parameter | Type | Description |
|---|---|---|
source_currency | string | Source currency code (ISO 4217, e.g., "USD", "EUR", "USDC", "USDT") |
target_currency | string | Target currency code (ISO 4217, e.g., "NGN", "GBP") |
source_amount | string | Amount in source currency (decimal string, e.g., "1000.00") |
quote_type | string | Transaction type: EXCHANGE, WITHDRAWAL, DEPOSIT, SWAP, DIRECT_EXCHANGE, or TRANSFER |
payment_method | string | Funding method: FIAT or CRYPTO |
tz | string | Request timezone (IANA format, e.g., "UTC", "America/New_York") |
Optional Parameters
| Parameter | Type | Description |
|---|---|---|
beneficiary_id | string (UUID) | Beneficiary ID. Required for EXCHANGE, DIRECT_EXCHANGE, and FIAT WITHDRAWAL; optional for DEPOSIT, SWAP, TRANSFER, and CRYPTO WITHDRAWAL. Create a beneficiary first using the Beneficiaries API (see Prerequisites) |
narration | string | Optional description for the quote |
on_behalf_of | string | Required for business API requests - ID of the customer (end user) the business is transacting for |
expected_source_interac_email | string (email) | Required for INTERAC transactions (non-WITHDRAWAL) |
payment_network | string | Crypto network when payment_method=CRYPTO (e.g., "ETH", "POLYGON") |
payment_address | string | Wallet address for crypto payments when payment_method=CRYPTO |
user_tag | string | Required for TRANSFER - Recipient's user tag on the Transfaar platform |
origin_reference | string | Required for business API requests - Unique transaction identifier for reconciliation (max 40 characters, must be unique) |
Quote Types
Quote types define the nature of the transaction and how funds move through the system:
-
DEPOSIT- Receive funds from an external source into your wallet. The source and target currency must be the same (e.g., NGNβNGN). For currencies with assigned Virtual Bank Accounts (VBAs), deposits happen automatically when funds arrive β no quote creation needed. For currencies requiring quote creation (currently CAD), you'll receive deposit instructions after accepting the quote. Note: For CAD deposits, payments must be sent from your linked Interac email address. The system uses a designated email address for processing, and payments from other email addresses will not be credited. This is a current limitation that may change in the future. -
WITHDRAWAL- Send funds from your wallet to an external beneficiary. The source and target currency must be the same (e.g., NGNβNGN). Requires sufficient wallet balance and an external beneficiary. -
SWAP- Convert funds between different currencies within your own wallets. Source and target currencies must be different (e.g., USDβEUR). Requires wallets for both currencies. The conversion happens immediately upon quote acceptance. -
EXCHANGE- Convert funds from your wallet and send to an external beneficiary in a different currency. This is equivalent to performing a SWAP followed by a WITHDRAWAL in one transaction. Source and target currencies must be different (e.g., USDβNGN). Requires sufficient wallet balance and an external beneficiary. -
TRANSFER- Send funds from your wallet to another user on the Transfaar platform using their user tag. Can be same or different currency. The recipient must have a wallet for the target currency. Transfers are processed immediately. -
DIRECT_EXCHANGE- Direct currency exchange that does not require a wallet balance. Source and target currencies must be different (e.g., USDβCAD). You specify the target beneficiary and receive payment instructions for the source currency. Once your deposit is received, the payout is automatically sent to the beneficiary. DIRECT_EXCHANGE and CAD deposits are the only quote types that provide payment instructions because funds don't affect your wallet β they go directly to the external beneficiary. Note: Currency compliance verification may be required for certain corridors.
Success Response (201 Created)
{
"quote_id": "123e4567-e89b-12d3-a456-426614174000",
"source": {
"currency": "USD",
"amount": "1000.00"
},
"target": {
"currency": "NGN",
"amount": "1500000.00"
},
"exchange_rate": "1500.00",
"narration": "Salary payment for John Doe",
"on_behalf_of": "123e4567-e89b-12d3-a456-426614174000",
"fees": {
"processing_fee": "10.00",
"deposit_fee": "5.00",
"payout_fee": "2.50",
"total_fees": "17.50",
"fee_currency": "USD"
},
"funding_method": {
"type": "BANKACCOUNT",
"reference": "REF-12345"
},
"total_payable": "1017.50",
"valid_until": "2025-03-09T01:40:53Z",
"quote_status": "CREATED",
"type": "EXCHANGE"
}Response Fields
| Field | Type | Description |
|---|---|---|
quote_id | string (UUID) | Unique identifier for the quote |
source | object | Source currency and amount |
target | object | Target currency and amount |
exchange_rate | string | Exchange rate used for conversion |
fees | object | Breakdown of all fees (processing, deposit, payout, total) |
funding_method | object | Payment method details (type, reference) |
total_payable | string | Total amount including all fees |
valid_until | string (ISO 8601) | Quote expiration timestamp |
quote_status | string | Current status (typically "CREATED") |
type | string | Quote type |
narration | string | Description provided in request |
on_behalf_of | string | Customer ID (for business API requests) |
Error Responses
| Status Code | Description |
|---|---|
400 | Invalid request format or missing required fields |
401 | Unauthorized - Invalid or missing JWT token |
404 | Fee configuration or related resource not found |
422 | Limit bounds or business rule violation (e.g., amount exceeds limits) |
500 | Internal server error |
Example: cURL
curl -X POST https://api.sznd.app/api/v1/client/quotes \
-H "X-API-Key: your-api-key" \
-H "X-Signature: generated-hmac-signature" \
-H "X-Timestamp: 1234567890" \
-H "Content-Type: application/json" \
-d '{
"source_currency": "USD",
"target_currency": "NGN",
"source_amount": "1000.00",
"beneficiary_id": "123e4567-e89b-12d3-a456-426614174000",
"quote_type": "EXCHANGE",
"payment_method": "FIAT",
"tz": "UTC",
"narration": "Salary payment",
"origin_reference": "ORDER-2025-001234",
"on_behalf_of": "123e4567-e89b-12d3-a456-426614174000"
}'Example: HTTP Request
POST /api/v1/client/quotes HTTP/1.1
Host: api.sznd.app
X-API-Key: your-api-key
X-Signature: generated-hmac-signature
X-Timestamp: 1234567890
Content-Type: application/json
{
"source_currency": "USD",
"target_currency": "NGN",
"source_amount": "1000.00",
"beneficiary_id": "123e4567-e89b-12d3-a456-426614174000",
"quote_type": "EXCHANGE",
"payment_method": "FIAT",
"tz": "UTC",
"narration": "Salary payment",
"origin_reference": "ORDER-2025-001234",
"on_behalf_of": "123e4567-e89b-12d3-a456-426614174000"
}Example: Crypto-Funded Quote
For crypto-funded quotes, include the payment network and address:
{
"source_currency": "USDC",
"target_currency": "NGN",
"source_amount": "1000.00",
"quote_type": "DEPOSIT",
"payment_method": "CRYPTO",
"payment_network": "ETH",
"payment_address": "0x1234abcd5678ef901234abcd5678ef90abcd1234",
"tz": "UTC"
}Get Quote By ID
Retrieve detailed information about a specific quote, including exchange rates, fees, status, and validity period.
Endpoint
GET /api/v1/client/quotes/{id}
Authentication
This endpoint requires API key authentication with HMAC signature. Include your API key and signature in the request headers:
X-API-Key: <your-api-key>
X-Signature: <hmac-signature>
X-Timestamp: <unix-timestamp>Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | The unique identifier of the quote to retrieve |
Success Response (200 OK)
{
"quote_id": "123e4567-e89b-12d3-a456-426614174000",
"source": {
"currency": "USD",
"amount": "1000.00"
},
"target": {
"currency": "NGN",
"amount": "1500000.00"
},
"exchange_rate": "1500.00",
"narration": "Salary payment for John Doe",
"on_behalf_of": "123e4567-e89b-12d3-a456-426614174000",
"fees": {
"processing_fee": "10.00",
"deposit_fee": "5.00",
"payout_fee": "2.50",
"total_fees": "17.50",
"fee_currency": "USD"
},
"funding_method": {
"type": "BANKACCOUNT",
"reference": "REF-12345"
},
"total_payable": "1017.50",
"valid_until": "2025-03-09T01:40:53Z",
"quote_status": "CREATED",
"type": "EXCHANGE"
}Response Fields
The response structure is identical to the Create Quote response. See the Create Quote section for field descriptions.
Error Responses
| Status Code | Description |
|---|---|
400 | Invalid quote ID format |
401 | Unauthorized - Invalid or missing JWT token |
403 | Forbidden - User does not own this quote |
404 | Quote not found |
500 | Internal server error |
Example: cURL
curl -X GET https://api.sznd.app/api/v1/client/quotes/123e4567-e89b-12d3-a456-426614174000 \
-H "X-API-Key: your-api-key" \
-H "X-Signature: generated-hmac-signature" \
-H "X-Timestamp: 1234567890"Example: HTTP Request
GET /api/v1/client/quotes/123e4567-e89b-12d3-a456-426614174000 HTTP/1.1
Host: api.sznd.app
X-API-Key: your-api-key
X-Signature: generated-hmac-signature
X-Timestamp: 1234567890
Content-Type: application/jsonUse Cases
- Check Quote Status - Verify if a quote is still valid before accepting it
- Display Quote Details - Show users the exchange rate, fees, and total payable amount
- Reconciliation - Retrieve quote details for transaction reconciliation
- Audit Trail - Access historical quote information for reporting
Important Notes
- Quote Ownership - You can only retrieve quotes that belong to your authenticated account
- Quote Expiration - Quotes expire after a set period (typically 30 minutes). Check the
valid_untilfield before accepting - Status Changes - Quote status may change after creation (e.g., from
CREATEDtoACCEPTEDorEXPIRED) - Rate Locking - Exchange rates are locked when the quote is created and remain valid until expiration
Accept Quote
Accept a quote to proceed with the transaction. Once accepted, the quote status changes and the payment process begins based on the quote type.
Endpoint
POST /api/v1/client/quotes/{id}/accept
Authentication
This endpoint requires API key authentication with HMAC signature. Include your API key and signature in the request headers:
X-API-Key: <your-api-key>
X-Signature: <hmac-signature>
X-Timestamp: <unix-timestamp>Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | The unique identifier of the quote to accept |
Success Response (200 OK)
{
"quote_id": "123e4567-e89b-12d3-a456-426614174000",
"transaction_id": "987e6543-e21b-43d2-b456-426614174111",
"transaction_reference": "TXN-REF-12345",
"payment_details": {
"quote_id": "123e4567-e89b-12d3-a456-426614174000",
"type": "NGN",
"reference": "REF-12345",
"ngn_payment_info": {
"account_number": "1234567890",
"bank_name": "Example Bank",
"account_name": "John Doe",
"payment_instructions": "Send payment to the account details above"
}
},
"total_payable": "1017.50",
"timeline": {
"created_at": "2025-03-09T01:10:53Z",
"accepted_at": "2025-03-09T01:15:30Z",
"estimated_completion": "2025-03-09T01:45:30Z"
},
"status": "AWAITING_PAYMENT"
}Response Fields
| Field | Type | Description |
|---|---|---|
quote_id | string (UUID) | The accepted quote identifier |
transaction_id | string (UUID) | The created transaction identifier |
transaction_reference | string | Unique reference for the transaction |
payment_details | object | Payment instructions (varies by quote type and payment method) |
total_payable | string | Total amount to be paid |
timeline | object | Timeline of quote and transaction events |
status | string | Current status after acceptance |
Error Responses
| Status Code | Description |
|---|---|
400 | Invalid quote ID format or quote already accepted |
401 | Unauthorized - Invalid or missing JWT token |
403 | Forbidden - User does not own this quote |
404 | Quote not found |
410 | Quote expired |
422 | Quote cannot be accepted (invalid state or business rule violation) |
500 | Internal server error |
Example: cURL
curl -X POST https://api.sznd.app/api/v1/client/quotes/123e4567-e89b-12d3-a456-426614174000/accept \
-H "X-API-Key: your-api-key" \
-H "X-Signature: generated-hmac-signature" \
-H "X-Timestamp: 1234567890" \
-H "Content-Type: application/json"Example: HTTP Request
POST /api/v1/client/quotes/123e4567-e89b-12d3-a456-426614174000/accept HTTP/1.1
Host: api.sznd.app
X-API-Key: your-api-key
X-Signature: generated-hmac-signature
X-Timestamp: 1234567890
Content-Type: application/jsonImportant Notes
- Quote Expiration - Quotes expire after a set period (typically 30 minutes). Ensure you accept before the
valid_untiltimestamp - Quote Ownership - You can only accept quotes that belong to your authenticated account
- Status Changes - After acceptance, the quote status changes to
AWAITING_PAYMENTorAWAITING_DEPOSITdepending on the quote type - Payment Instructions - The
payment_detailsfield is provided for DIRECT_EXCHANGE and CAD deposits. Other quote types don't require payment instructions since funds are processed automatically or use existing accounts (like VBAs for deposits). - Transaction Creation - Accepting a quote automatically creates a transaction that can be tracked using the
transaction_id
Use Cases
- Complete a Currency Exchange - Accept an exchange quote to initiate the conversion
- Initiate a Deposit - Accept a deposit quote (only for currencies requiring quote creation, currently CAD)
- Process a Withdrawal - Accept a withdrawal quote to begin the payout process
Complete Transaction Workflow
For Transactions Requiring Quote Creation (WITHDRAWAL, EXCHANGE, SWAP, TRANSFER, DIRECT_EXCHANGE)
-
Create Quote β
POST /api/v1/client/quotes- Get locked rates, fees, and expiration time
- Store
quote_idfor next steps
-
Accept Quote β
POST /api/v1/client/quotes/{id}/accept- Creates transaction automatically
- Returns
transaction_id - For DIRECT_EXCHANGE and CAD deposits: Returns payment instructions in
payment_details - Quote status changes to
AWAITING_PAYMENTorAWAITING_DEPOSIT
-
Process Payment β Follow instructions (DIRECT_EXCHANGE and CAD deposits only)
- For DIRECT_EXCHANGE and CAD deposits: Send funds using payment instructions from accept response
- For other types: Funds are processed automatically (no instructions needed)
-
Track Status β Monitor until completion
- Polling:
GET /api/v1/client/quotes/{id}orGET /api/v1/client/transactions/{id} - Webhooks: Configure webhook URL to receive real-time status updates
- Status progresses:
AWAITING_PAYMENTβPAYMENT_CONFIRMEDβPROCESSING_PAYOUTβCOMPLETED
- Polling:
-
Reconcile β Match webhook events with your records
- Use
transaction_idandtransaction_referencefrom accept response - Match
origin_referencewith your system's transaction ID
- Use
For Deposits with Virtual Bank Accounts (No Quote Creation Required)
- Funds Arrive β User sends funds to their assigned Virtual Bank Account
- System Processes β Quote and transaction created automatically via webhook
- Wallet Credited β Funds automatically credited to user's wallet
- Track Status β Monitor via webhooks or polling
GET /api/v1/client/transactions/{id}
Important:
- Quotes expire after ~30 minutes β accept before
valid_untiltimestamp - Always provide unique
origin_referencefor idempotency (when creating quotes) - Set up webhooks for real-time updates (recommended)
- Handle
422errors for limit violations gracefully - Payment instructions are provided for DIRECT_EXCHANGE and CAD deposits β other quote types process funds automatically
π See also:
- Transactions API - Track transaction status
- Webhooks - Set up webhook notifications
- Beneficiaries API - Manage recipients