Resources
Quotes

Quote

**Quote ** powers business flows such as deposits, withdrawals and currency exchanges.
Quotes lock in rates and fees for a limited time and drive both funding instructions and payout execution.

High-level concepts

  • Quote: a priced offer describing source/target currencies, amounts, fees, and validity window.
  • Funding method: how the quote is funded (wallet, bank/Interac, card, crypto, etc.).
  • Quote type: EXCHANGE, DEPOSIT, or WITHDRAWAL.
  • Status lifecycle:
    • CREATED → quote generated, not yet accepted.
    • AWAITING_PAYMENT / AWAITING_DEPOSIT → quote accepted, waiting for funds.
    • PAYMENT_CONFIRMED / DEPOSIT_CONFIRMED → funds secured.
    • PROCESSING_PAYOUT → payout leg in progress.
    • COMPLETED, EXPIRED, or FAILED → terminal states.

Quote flows

The quote system supports advanced business use‑cases with payment tracking and crypto funding:

  • Adds dedicated payment tracking fields to the quotes table:
    • payment_method, payment_currency, payment_network, payment_address, payment_sender_name.
    • payment_source_amount, payment_source_to_usd_rate, payment_usd_to_target_rate, payment_target_amount.
  • Supports crypto funding via stablecoins (e.g. USDC/USDT) by bridging through USD for accurate fee and limit calculations.

Crypto quote behaviour

For crypto‑funded quotes, the system:

  • Validates payment_method == CRYPTO and ensures the requested token/network are supported.
  • Maps display currencies (what the business sees) to internal quote currencies and payment currencies, depending on quote type:
    • DEPOSIT: user funds with stablecoin → receives fiat; fees calculated on USD equivalent.
    • WITHDRAWAL: user holds fiat → receives stablecoin; fiat side limits enforced.
    • DIRECT_EXCHANGE: stablecoin → fiat via USD bridge.
  • Uses USD as an intermediate currency to:
    • Compute exchange rates.
    • Calculate and convert fees correctly between stablecoin and fiat.
    • Derive the final total payable amount in the asset the user actually transfers.

How /business integrates with quotes

Business clients typically interact with quotes as part of a broader /business integration:

  • Authentication

    • All quote‑related calls from business systems must be signed using the HMAC scheme described in the Authentication section, even when the underlying path is not prefixed with /business internally.
  • Webhook notifications

    • When a quote leads to a completed transaction and the owner is a business user with a configured webhook URL, the Business Webhook System sends a unified webhook payload with:
      • transaction_type matching the quote type (DEPOSIT/WITHDRAWAL/EXCHANGE).
      • status reflecting the final transaction state.
      • reference and transaction_id for reconciliation.
  • Reconciliation & reporting

    • Business systems can combine webhook events with quote responses to:
      • Reconcile fees and total payable amounts.
      • Track conversion and completion rates for quotes.
      • Monitor limits and declined requests (e.g. 422 responses for limit violations).

/business endpoint from the OpenAPI spec

From docs/openapi.yaml, the following /business route is explicitly defined and is typically used before initiating quotes or payouts for a new contact:

Onboard a business contact using Footprint

  • Method: POST
  • Path: /business/contact/onboard
  • Summary: Onboard a business contact using a Footprint KYC token.

Request body (from the OpenAPI spec):

{
  "token_id": "fp_token_xyz"
}
  • token_id (string, required): Footprint token ID for the KYC session.

Successful response (200)User schema (from components.schemas.User):

{
  "id": "d290f1ee-6c54-4b01-90e6-d701748f0851",
  "email": "business.contact@example.com",
  "first_name": "Jane",
  "middle_name": "A.",
  "last_name": "Doe",
  "phone_number": "+2348012345678",
  "tag": "business-contact",
  "role": "CUSTOMER",
  "user_type": "BUSINESS",
  "user_status": "ACTIVE",
  "kyc_status": "APPROVED",
  "title": "Ms",
  "date_of_birth": "1990-01-01T00:00:00Z",
  "avatar_url": "https://cdn.transfaar.com/avatars/jane.png",
  "is_email_verified": true,
  "is_totp_2fa_activated": false,
  "country_code": "CA",
  "address_line_1": "123 Example Street",
  "address_line_2": "Suite 4B",
  "postal_code": "A1B2C3",
  "city": "Toronto",
  "province": "ON",
  "created_at": "2025-01-30T12:20:15Z",
  "updated_at": "2025-01-30T12:20:15Z"
}

Error responses (from the OpenAPI spec):

  • 400 – Token is required (Error schema).
  • 403 – Unmatched email for user record against Footprint email (Error schema).
  • 500 – Internal server error (Error schema).

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.

Endpoint

POST /api/v1/quotes/v2

Authentication

This endpoint requires JWT authentication. Include your access token in the Authorization header:

Authorization: Bearer <your-access-token>

Request Body

{
  "source_currency": "USD",
  "target_currency": "NGN",
  "source_amount": "1000.00",
  "beneficiary_id": "123e4567-e89b-12d3-a456-426614174000",
  "fee_config_id": "2fbdb973-39fd-4217-aa9b-e7b8ccc9e457",
  "quote_type": "EXCHANGE",
  "payment_method": "FIAT",
  "tz": "UTC",
  "narration": "Salary payment for John Doe"
}

Required Parameters

ParameterTypeDescription
source_currencystringSource currency code (ISO 4217, e.g., "USD", "EUR")
target_currencystringTarget currency code (ISO 4217, e.g., "NGN", "GBP")
source_amountstringAmount in source currency (decimal string, e.g., "1000.00")
fee_config_idstring (UUID)Fee configuration ID for the selected payment rail
quote_typestringTransaction type: EXCHANGE, WITHDRAWAL, DEPOSIT, SWAP, DIRECT_EXCHANGE, or TRANSFER
payment_methodstringFunding method: FIAT or CRYPTO
tzstringRequest timezone (IANA format, e.g., "UTC", "America/New_York")

Optional Parameters

ParameterTypeDescription
beneficiary_idstring (UUID)Beneficiary ID. Required for EXCHANGE, DIRECT_EXCHANGE, and FIAT WITHDRAWAL; optional for DEPOSIT, SWAP, TRANSFER, and CRYPTO WITHDRAWAL
narrationstringOptional description for the quote
expected_source_interac_emailstring (email)Required for INTERAC transactions (non-WITHDRAWAL)
payment_networkstringCrypto network when payment_method=CRYPTO (e.g., "ETH", "POLYGON")
payment_addressstringWallet address for crypto payments when payment_method=CRYPTO
user_tagstringUser tag for TRANSFER transactions
origin_referencestringOrigin reference for external client APIs

Quote Types

  • EXCHANGE - Convert one currency to another
  • WITHDRAWAL - Withdraw funds to a beneficiary
  • DEPOSIT - Deposit funds into your account
  • SWAP - Swap between currencies
  • DIRECT_EXCHANGE - Direct currency exchange
  • TRANSFER - Transfer funds between users (V2 feature)

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",
  "fees": {
    "processing_fee": "10.00",
    "deposit_fee": "5.00",
    "payout_fee": "2.50",
    "total_fees": "17.50",
    "fee_currency": "USD"
  },
  "funding_method": {
    "type": "BANKACCOUNT",
    "provider_id": 1,
    "provider_name": "Payaza",
    "provider_reference": "PAY-REF-12345"
  },
  "total_payable": "1017.50",
  "valid_until": "2025-03-09T01:40:53Z",
  "quote_status": "CREATED",
  "type": "EXCHANGE"
}

Response Fields

FieldTypeDescription
quote_idstring (UUID)Unique identifier for the quote
sourceobjectSource currency and amount
targetobjectTarget currency and amount
exchange_ratestringExchange rate used for conversion
feesobjectBreakdown of all fees (processing, deposit, payout, total)
funding_methodobjectPayment method details (type, provider, reference)
total_payablestringTotal amount including all fees
valid_untilstring (ISO 8601)Quote expiration timestamp
quote_statusstringCurrent status (typically "CREATED")
typestringQuote type
narrationstringDescription provided in request

Error Responses

Status CodeDescription
400Invalid request format or missing required fields
401Unauthorized - Invalid or missing JWT token
404Fee configuration or related resource not found
422Limit bounds or business rule violation (e.g., amount exceeds limits)
500Internal server error

Example: cURL

curl -X POST /api/v1/quotes/v2 \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  -H "Content-Type: application/json" \
  -d '{
    "source_currency": "USD",
    "target_currency": "NGN",
    "source_amount": "1000.00",
    "beneficiary_id": "123e4567-e89b-12d3-a456-426614174000",
    "fee_config_id": "2fbdb973-39fd-4217-aa9b-e7b8ccc9e457",
    "quote_type": "EXCHANGE",
    "payment_method": "FIAT",
    "tz": "UTC",
    "narration": "Salary payment"
  }'

Example: HTTP Request

POST /api/v1/quotes/v2 HTTP/1.1
Host: api.sznd.app
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

{
  "source_currency": "USD",
  "target_currency": "NGN",
  "source_amount": "1000.00",
  "beneficiary_id": "123e4567-e89b-12d3-a456-426614174000",
  "fee_config_id": "2fbdb973-39fd-4217-aa9b-e7b8ccc9e457",
  "quote_type": "EXCHANGE",
  "payment_method": "FIAT",
  "tz": "UTC",
  "narration": "Salary payment"
}

Example: Crypto-Funded Quote

For crypto-funded quotes, include the payment network and address:

{
  "source_currency": "USDC",
  "target_currency": "NGN",
  "source_amount": "1000.00",
  "fee_config_id": "2fbdb973-39fd-4217-aa9b-e7b8ccc9e457",
  "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/quotes/{id}

Authentication

This endpoint requires JWT authentication. Include your access token in the Authorization header:

Authorization: Bearer <your-access-token>

Path Parameters

ParameterTypeDescription
idstring (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",
  "fees": {
    "processing_fee": "10.00",
    "deposit_fee": "5.00",
    "payout_fee": "2.50",
    "total_fees": "17.50",
    "fee_currency": "USD"
  },
  "funding_method": {
    "type": "BANKACCOUNT",
    "provider_id": 1,
    "provider_name": "Payaza",
    "provider_reference": "PAY-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 CodeDescription
400Invalid quote ID format
401Unauthorized - Invalid or missing JWT token
403Forbidden - User does not own this quote
404Quote not found
500Internal server error

Example: cURL

curl -X GET /api/v1/quotes/123e4567-e89b-12d3-a456-426614174000 \
  -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."

Example: HTTP Request

GET /api/v1/quotes/123e4567-e89b-12d3-a456-426614174000 HTTP/1.1
Host: api.sznd.app
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
Content-Type: application/json

Use 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

  1. Quote Ownership - You can only retrieve quotes that belong to your authenticated account
  2. Quote Expiration - Quotes expire after a set period (typically 30 minutes). Check the valid_until field before accepting
  3. Status Changes - Quote status may change after creation (e.g., from CREATED to ACCEPTED or EXPIRED)
  4. Rate Locking - Exchange rates are locked when the quote is created and remain valid until expiration

Next Steps

After creating a quote, you'll typically want to:

  1. Accept the Quote - Use the quote ID to accept and proceed with the transaction
  2. Monitor Status - Poll the quote status or set up webhooks to track quote lifecycle
  3. Handle Expiration - Create a new quote if the current one expires before acceptance

For more information, see:

  • Accept Quote - How to accept a quote and initiate the transaction
  • Webhooks - Set up webhooks to receive real-time quote status updates