Convert Currency

Execute a currency conversion. You can optionally provide a quoteId to use a previously locked-in rate.

POST /v1/conversions

Headers

Header Required Description
X-Api-Key Yes Your API key
X-Idempotency-Key Yes Unique key to prevent duplicate conversions
Content-Type Yes application/json

Request Body

Field Type Required Description
amount number Yes Amount in source currency (see minimum amounts below)
sourceCurrency string Yes Source currency: NGN, USD, EUR, GBP, BTC, USDT, USDC
targetCurrency string Yes Target currency: NGN, USD, EUR, GBP, BTC, USDT, USDC
quoteId string No UUID of an existing quote to execute with its locked-in rate
accountId number No ID of the virtual account to debit when sourceCurrency is NGN. Ignored for non-NGN sources. If omitted on an NGN-source conversion, the first available NGN account is used.

NGN bank account requirement: Any conversion involving NGN (as either the source or the target currency) requires the account to have an existing NGN virtual account. Create one via the virtual account endpoints before calling this endpoint with NGN on either side.

Minimum Amounts

Source Currency Minimum Amount
NGN 150,000
BTC 0.00033
USD, EUR, GBP, USDT, USDC 15

Note: sourceCurrency and targetCurrency must be different.

Example Request

Without a quote

curl -X POST "https://api.esca.finance/v1/conversions" \
  -H "X-Api-Key: your_api_key_here" \
  -H "X-Idempotency-Key: conv-550e8400-e29b-41d4-a716-446655440000" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 500000,
    "sourceCurrency": "NGN",
    "targetCurrency": "USD"
  }'

With a quote

curl -X POST "https://api.esca.finance/v1/conversions" \
  -H "X-Api-Key: your_api_key_here" \
  -H "X-Idempotency-Key: conv-550e8400-e29b-41d4-a716-446655440001" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 500000,
    "sourceCurrency": "NGN",
    "targetCurrency": "USD",
    "quoteId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }'

With a specific account

curl -X POST "https://api.esca.finance/v1/conversions" \
  -H "X-Api-Key: your_api_key_here" \
  -H "X-Idempotency-Key: conv-550e8400-e29b-41d4-a716-446655440002" \
  -H "Content-Type: application/json" \
  -d '{
    "amount": 500000,
    "sourceCurrency": "NGN",
    "targetCurrency": "USD",
    "accountId": 12345
  }'

Example Response

{
  "status": true,
  "message": "Conversion Successful",
  "data": {
    "conversionId": "f7a8b9c0-d1e2-3456-abcd-ef7890123456",
    "sourceCurrency": "NGN",
    "targetCurrency": "USD",
    "sourceAmount": 500000,
    "targetAmount": 312.50,
    "appliedRate": 1600,
    "status": "COMPLETED",
    "quoteId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
  }
}

Response Fields

Field Type Description
conversionId string UUID of the conversion. Use this to check the conversion status.
sourceCurrency string Source currency
targetCurrency string Target currency
sourceAmount number Amount debited in source currency
targetAmount number Amount credited in target currency
appliedRate number Exchange rate applied
status string PROCESSING, COMPLETED, or FAILED
quoteId string Quote UUID (only present if a quote was used)

Error Responses

Same currency

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Source and target currencies must be different."
}

No NGN account

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "No NGN virtual account found. Please create one before converting."
}

Account not found

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "The specified NGN virtual account was not found."
}

Quote currency mismatch

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Quote currencies (NGN -> EUR) do not match request (NGN -> USD)."
}

Insufficient balance

The exact message depends on which constraint failed:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Insufficient balance"
}

When part of the balance is available now and the rest is pending settlement:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "Insufficient balance. You can swap up to 500.00 USDT at this time."
}

When the requested amount is fully covered by the ledger but a pending transaction is still settling:

{
  "statusCode": 400,
  "error": "Bad Request",
  "message": "You can swap up to 500.00 USDT now, or 1000.00 USDT once your pending transaction settles."
}

Duplicate request

{
  "statusCode": 409,
  "message": "Duplicate request"
}

Webhooks

When a conversion is executed, the following webhook events may be dispatched:

Event When
exchange.processing Conversion is being processed asynchronously
exchange.completed Conversion completed successfully
exchange.failed Conversion failed

See Webhook Event Payloads for payload details.