A conversion debits one currency from a customer’s account and credits another currency to
a destination account at a specified exchange rate. It is a balance-to-balance operation
within the platform — no external payment is involved.For example, converting USD to EUR debits the customer’s USD account and credits their EUR
account. The customer sees “I converted 10,000 USD to 9,250 EUR.” No internal settlement
or liquidity mechanisms are exposed.
Conversions are for standalone balance operations where a customer wants to change
the currency they hold. For cross-currency payments to external counterparties, use
POST /payments with executionPreference: use_quote or at_market instead — the
payment endpoint handles FX and delivery in a single call.
Provide a quoteId from a previously created FX quote. The conversion executes at the
locked rate. This is the recommended approach when rate certainty matters.
Omit quoteId and provide the asset pair and amount directly. The conversion executes
at the current market rate. Use this when speed matters more than rate certainty.
At-market conversions execute at the prevailing rate, which may differ from the last
indicative rate you displayed. For large amounts or volatile pairs, use a quote-based
conversion to guarantee the rate.
Here is a complete flow: discover pairs, lock a quote, and execute a conversion.
Copy
import requestsimport uuidBASE_URL = "https://sandbox.api.openfx.com/v1"HEADERS = { "Authorization": f"Bearer {api_key}", "X-Signature": signature, "X-Timestamp": timestamp, "Content-Type": "application/json",}# Step 1: Verify the pair is availablepairs_resp = requests.get(f"{BASE_URL}/fx/asset-pairs", headers=HEADERS)pairs = pairs_resp.json()usd_gbp = next( (p for p in pairs["items"] if p["sellCurrency"] == "USD" and p["buyCurrency"] == "GBP"), None,)if not usd_gbp: raise ValueError("USD/GBP pair not available")print(f"Pair available. Min: {usd_gbp['minAmount']}, Max: {usd_gbp['maxAmount']}")# Step 2: Lock a quotequote_resp = requests.post( f"{BASE_URL}/fx/quotes", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, json={ "sellCurrency": "USD", "buyCurrency": "GBP", "sellAmount": "10000.00", },)quote = quote_resp.json()print(f"Quote locked: {quote['id']} at rate {quote['rate']}")print(f"You sell: {quote['sellAmount']} USD")print(f"You get: {quote['buyAmount']} GBP")print(f"Expires: {quote['expiresAt']}")# Step 3: Execute the conversion (immediately, while quote is active)conversion_resp = requests.post( f"{BASE_URL}/fx/conversions", headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())}, json={ "quoteId": quote["id"], "sellCurrency": "USD", "buyCurrency": "GBP", "sellAmount": "10000.00", "sourceAccountId": "acc_01953e1a5f4b7002", "destinationAccountId": "acc_01953e1a5f4b7003", },)conversion = conversion_resp.json()print(f"Conversion {conversion['id']}: {conversion['status']}")
For cross-currency payments to external counterparties, you do not need to create a
separate conversion. Use POST /payments with executionPreference: use_quote (to
reference an FX quote) or executionPreference: at_market (to convert at the current
rate). The payment endpoint handles FX conversion and delivery in one operation.