On/Off-Ramp, and cross-chain Swap via CeFi
Beta FeatureThe Trading API is currently in beta and subject to change. For participation details, contact your Fireblocks Customer Success Manager or email [email protected].
This guide provides step-by-step examples of how to execute various order operations using the Fireblocks Trading API via account-based providers. These require you to connect an account before trading. For instructions on how to connect accounts, see Fireblocks Connected Accounts. This guide covers multiple use cases including on-ramp (fiat to crypto), off-ramp (crypto to fiat), and bridging (crypto-to-crypto).
Prerequisites
Before you begin, ensure you have completed the prerequisites outlined in the Trading API Overview:
- ✅ Fireblocks API credentials configured
- ✅ Fireblocks TypeScript SDK installed (
@fireblocks/version 13.x or later) - ✅ Connected account(s) set up with your chosen provider(s) via the Fireblocks Console (see Fireblocks Connected Accounts for setup instructions)
SDK Setup
First, set up your Fireblocks SDK client:
import { Fireblocks } from '@fireblocks/ts-sdk';
import * as fs from 'fs';
// Initialize the Fireblocks SDK
const fireblocks = new Fireblocks({
apiKey: 'your-api-key',
secretKey: fs.readFileSync('/path/to/your/secret.key', 'utf8'),
basePath: 'https://api.fireblocks.io',
});Provider and account discovery
Before trading with account-based providers, find out which providers are available and which accounts you have connected. If you haven't connected any accounts yet, see Fireblocks Connected Accounts for setup instructions.
Step 1: Get Providers and Connected Accounts
Retrieve all trading providers. For account-based providers, the response includes provider information and connected accounts, allowing you to extract both providerId and accountId in a single call.
// Get all trading providers
const response = await fireblocks.trading.getTradingProviders({ pageSize: 20 });
// Filter for account-based providers
const accountBasedProviders = response.data.data.filter(p => p.accountBased);
// Access provider and account information
for (const provider of accountBasedProviders) {
console.log(`Provider: ${provider.id} (${provider.name})`);
provider.accounts?.forEach(account => {
console.log(` Account: ${account.id} (${account.name})`);
});
}Response Example
{
"data": [
{
"id": "ALFREDPAY",
"name": "Alfred Pay",
"accountBased": true,
"connected": true,
"accounts": [
{
"id": "acc_5e9a2d1c4b7f3e8a",
"name": "My Alfred Pay Account"
}
],
"manifest": {
"assetTypes": ["FIAT", "DIGITAL"],
"capabilities": ["TRADING"]
}
},
{
"id": "YELLOWCARD",
"name": "Yellow Card",
"accountBased": true,
"connected": true,
"accounts": [
{
"id": "acc_9f4e2d8b1c6a5e73",
"name": "Yellow Card Main Account"
}
],
"manifest": {
"assetTypes": ["FIAT", "DIGITAL"],
"capabilities": ["TRADING"]
}
}
],
"total": 2,
"next": null
}Key Fields Explained
| Field | Description |
|---|---|
id | Unique identifier for the provider (use as providerId in subsequent API calls) |
name | Display name of the provider |
accountBased | true for account-based providers, false for direct access providers |
connected | Whether you have at least one connected account with this provider |
accounts | Array of connected accounts for this provider. Each account has an id (use as accountId in subsequent API calls) and name |
For more details about this endpoint, see the Get Providers API Reference.
Step 2: Get Supported Trading Pairs
For each connected account, discover which trading pairs are supported:
// Get supported trading pairs for a specific connected account
const response = await fireblocks.trading.getTradingPairs({
accountId: 'acc_9f4e2d8b1c6a5e73',
});
// Response data
const tradingPairs = response.data;
// tradingPairs = [
// {
// "id": "7c9e8f2a-4b5d-4e1c-9a3b-6f8d2e5c7a1b",
// "toAsset": "USDC",
// "fromAsset": "USD",
// "prefunded": false,
// "fromAssetRail": "ACH"
// }
// ]Step 3: Get Indicative Rates
Get indicative rates for price preview (these are not executable quotes):
// Get indicative rates
const response = await fireblocks.trading.getRates({
accountId: 'acc_9f4e2d8b1c6a5e73',
baseAssetId: 'USD',
quoteAssetId: 'BTC',
});
const rates = response.data;
Note: Rates provide indicative prices for preview, while quotes return committed rates that can be executed until expiration.
Clarification on how to translating user intent into baseAssetId, quoteAssetId, side, and baseAmount
When creating a Quote or an Order, you express the trade using:
baseAssetId: the asset you receive on BUY / give on SELLquoteAssetId: the counter asset used to pay/receiveside:BUY: receive base / pay quoteSELL: give base / receive quote
baseAmount: amount inbaseAssetIdBUY: base amount to receiveSELL: base amount to sell
Examples
| Intent | baseAssetId | quoteAssetId | side | baseAmount |
|---|---|---|---|---|
| Buying 100 BTC with USD | BTC | USD | BUY | 100 |
| Buying 100 USD with BTC | USD | BTC | BUY | 100 |
| Selling 100 BTC for USD | BTC | USD | SELL | 100 |
| Selling 100 USD for BTC | USD | BTC | SELL | 100 |
Participants & compliance
Participant details vary by provider and rail. The participantsIdentification object defines the originator and beneficiary involved in an order.
Example structure
{
"participantsIdentification": {
"originator": {
"externalReferenceId": "user_123",
"participantRelationshipType": "FirstParty",
"entityType": "INDIVIDUAL"
},
"beneficiary": {
"participantRelationshipType": "ThirdParty",
"fullName": {
"firstName": "Alice",
"lastName": "Lee"
}
}
}
}Key concepts
- First-party: Acting for self — provider already holds KYC; minimal data required.
- Third-party: Acting for another — provider may require full PII.
The level of PII data required depends on the provider and the relationship type (first-party vs. third-party).
Use Case Examples
The following sections demonstrate different trading use cases with account-based providers:
Use Case 1: On-Ramp - DVP Settlement with Market Execution
Use Case: Convert fiat to crypto at the market rate. The user creates the order, receives payment instructions from the provider, deposits the funds, and once payment is confirmed, the provider executes and settles the crypto, ensuring delivery versus payment (DVP).
Settlement Type: DVP (Delivery vs Payment)
Execution Type: Market
Note: ThebaseAssetId,baseAssetRail,quoteAssetId, andquoteAssetRailvalues used in the order must match a supported trading pair returned from thegetTradingPairsendpoint (see Step 2 in Getting Started). This ensures the provider supports the specific asset and rail combination you're requesting.
Step 1: Create the Order
// Create on-ramp order with DVP settlement and market execution
const response = await fireblocks.trading.createOrder({
createOrderRequest: {
via: {
type: 'PROVIDER_ACCOUNT',
providerId: 'bridge-provider-001',
accountId: 'acc_9f4e2d8b1c6a5e73',
},
executionRequestDetails: {
type: 'MARKET',
side: 'BUY',
baseAmount: '1000',
baseAssetId: 'USD',
baseAssetRail: 'ACH',
quoteAssetId: 'USDC',
quoteAssetRail: 'BLOCKCHAIN',
},
settlement: {
type: 'DVP',
sourceAccount: {
type: 'EXTERNAL',
},
destinationAccount: {
type: 'ONE_TIME_ADDRESS',
address: '1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa',
},
},
participantsIdentification: {
originator: {
entityType: 'BUSINESS',
participantRelationshipType: 'FirstParty',
},
beneficiary: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'ThirdParty',
fullName: {
lastName: 'Johnson',
firstName: 'Alexander',
},
postalAddress: {
streetName: 'Fifth Avenue',
buildingNumber: '350',
postalCode: '10118',
city: 'New York',
subdivision: 'NY',
district: 'Manhattan',
country: 'US',
},
externalReferenceId: 'person_ref_7f3e2d1c4b8a5e9f',
dateOfBirth: '1985-03-15',
},
},
customerInternalReferenceId: '32e423',
},
idempotencyKey: `order-${Date.now()}`,
});
const order = response.data;Step 2: Handle Payment Instructions
Since the settlement type is DVP and the source type is EXTERNAL, the funds will move from outside Fireblocks. The order creation response will include payment instructions for the rail which you select (e.g., ACH, SEPA, Wire):
{
"paymentInstructions": {
"referenceId": "REF-ACH-001",
"type": "ACH",
"address": {
"accountHolder": {
"name": "Bridge Provider Ltd.",
"address": "123 Main Street",
"city": "New York",
"country": "US",
"subdivision": "NY",
"postalCode": "10001"
},
"bankName": "JPMorgan Chase Bank N.A.",
"bankAccountNumber": "9876543210",
"routingNumber": "021000021",
"accountType": "CHECKING"
}
}
}Considerations
- For third-party payouts, like the one in the example, the provider must receive the beneficiary details (PII as required by the provider). In this case, you are the originator — acting as a first party, already KYC'd with the provider. Therefore, the only data needed is to set the
beneficiary.participantRelationshipType = "FirstParty". - Since the settlement type is DVP and the source type is EXTERNAL, the funds will move from outside Fireblocks. As a result, the order creation response will include payment instructions for the rail which you select (e.g., ACH, SEPA, Wire).
Use Case 2: On-Ramp - Prefunded settlement with quote execution
Use Case: Convert fiat to crypto at a locked rate from a committed quote. Funds are already held in the account; no payment instructions are returned in the response, and the provider will execute and settle the request immediately.
Settlement Type: Prefunded
Execution Type: Quote
Step 1: Create a Quote
// Create a quote for on-ramp
const quoteResponse = await fireblocks.trading.createQuote({
createQuote: {
scope: [
{
providerId: 'SCRYPT',
accountId: 'scrypt_acc_5e9a2d1c4b7f3e8a',
},
],
side: 'BUY',
baseAssetId: 'USDT_ERC20',
quoteAssetId: 'TRX_USDT_S2UZ',
baseAmount: '15000',
},
idempotencyKey: `quote-${Date.now()}`,
});
const quote = quoteResponse.data.quotes[0];In the quote response, you will receive all related metadata, including the quote ID (id) and expiration time (expiresAt). The quote ID is then used in the next step to create an order and execute the trade.
Step 2: Execute order with quote
// Execute order using the quote from Step 1
const response = await fireblocks.trading.createOrder({
createOrderRequest: {
via: {
type: 'PROVIDER_ACCOUNT',
accountId: 'acc_5e9a2d1c4b7f3e8a',
providerId: 'ALFREDPAY',
},
executionRequestDetails: {
type: 'QUOTE',
reQuote: {
type: 'MARKET',
},
quoteId: 'quote_8f2e4d1a9c5b7e3f',
},
settlement: {
type: 'PREFUNDED',
destinationAccount: {
type: 'VAULT_ACCOUNT',
accountId: 'vault_acc_9f3e2d1c4b8a7e5f',
},
},
participantsIdentification: {
originator: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
beneficiary: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
},
},
idempotencyKey: `order-${Date.now()}`,
});
const order = response.data;Considerations
- In this example, you perform an on-ramp for yourself, not for a third-party recipient. Therefore, both the originator and beneficiary use
"participantRelationshipType": "FirstParty", and no additional PII data is required. - The
quoteIdused in the order request is the same ID returned in the response from thePOST /trading/quotescall.
Use Case 3: Off-Ramp - DVP settlement with market execution
Use Case: Convert crypto to fiat at the market rate. The provider waits for confirmation of the crypto deposits before finalizing the settlement, ensuring delivery versus payment (DVP).
Settlement Type: DVP
Execution Type: Market
Note: ThebaseAssetId,baseAssetRail,quoteAssetId, andquoteAssetRailvalues used in the order must match a supported trading pair returned from thegetTradingPairsendpoint (see Step 2 in Getting Started). This ensures the provider supports the specific asset and rail combination you're requesting.
Step 1: Create the Order
// Create off-ramp order with DVP settlement and market execution
const response = await fireblocks.trading.createOrder({
createOrderRequest: {
via: {
type: 'PROVIDER_ACCOUNT',
providerId: 'YELLOWCARD',
accountId: 'acc_9f4e2d8b1c6a5e73',
},
executionRequestDetails: {
type: 'MARKET',
side: 'BUY',
baseAmount: '250',
baseAssetId: 'XOF',
baseAssetRail: 'LOCAL_BANK_TRANSFER_AFRICA',
quoteAssetId: 'USDT_ERC20',
quoteAssetRail: 'BLOCKCHAIN',
},
settlement: {
type: 'DVP',
sourceAccount: {
type: 'VAULT_ACCOUNT',
accountId: 'vault_acc_5e9a2d1c4b7f3e8a',
},
destinationAccount: {
type: 'EXTERNAL_WALLET',
accountId: 'fiat_whitelisted_acc_9f3e2d1c4b8a7e5f',
},
},
participantsIdentification: {
originator: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
beneficiary: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
},
},
idempotencyKey: `order-${Date.now()}`,
});
const order = response.data;Considerations
- In this example, you perform an off-ramp for yourself, not for a third-party recipient. Therefore, both the originator and beneficiary use
"participantRelationshipType": "FirstParty", and no additional PII data is required. - In this example, you chose to use a whitelisted account as the destination fiat account type. This allows you to register and manage external bank accounts (and also crypto addresses) directly within Fireblocks, ensuring secure, verified destinations that can be safely reused for future orders and transactions.
- Since the source of this order is a Vault Account, once the provider receives the order request, a transfer request will be automatically created from your vault to the provider. You will then need to approve and sign this transfer in accordance with the workspace's policy rules before the order can be executed.
Use Case 4: Bridging (Crypto-to-Crypto) - DVP settlement with quote execution
Use Case: Execute a cross-chain bridging operation through the provider's connected accounts. In this flow, the user swaps USDT on Ethereum for USDT on Tron using their Scrypt provider account.
Settlement Type: DVP
Execution Type: Quote
Step 1: Create a Quote
// Create a quote for crypto-to-crypto bridging
const quoteResponse = await fireblocks.trading.createQuote({
createQuote: {
scope: [
{
providerId: 'SCRYPT',
accountId: 'scrypt_acc_5e9a2d1c4b7f3e8a',
},
],
side: 'BUY',
baseAssetId: 'USDT_ERC20',
quoteAssetId: 'TRX_USDT_S2UZ',
baseAmount: '15000',
},
idempotencyKey: `quote-${Date.now()}`,
});
const quote = quoteResponse.data.quotes[0];In the quote response, you will receive all related metadata, including the quote ID (id) and expiration time (expiresAt). The quote ID is then used in the next step to create an order and execute the trade.
Step 2: Execute Order with Quote
// Execute bridging order using the quote from Step 1
const response = await fireblocks.trading.createOrder({
createOrderRequest: {
via: {
type: 'PROVIDER_ACCOUNT',
providerId: 'SCRYPT',
accountId: 'scrypt_acc_5e9a2d1c4b7f3e8a',
},
executionRequestDetails: {
type: 'QUOTE',
reQuote: {
type: 'MARKET',
},
quoteId: 'quote_khge4d1a9c5bmvby',
},
settlement: {
type: 'DVP',
sourceAccount: {
type: 'VAULT_ACCOUNT',
accountId: 'vault_acc_5e9a2d1c4b7f3e8a',
},
destinationAccount: {
type: 'VAULT_ACCOUNT',
accountId: 'vault_acc_5e9a2d1c4b7f3e8a',
},
},
participantsIdentification: {
originator: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
beneficiary: {
entityType: 'INDIVIDUAL',
participantRelationshipType: 'FirstParty',
},
},
},
idempotencyKey: `order-${Date.now()}`,
});
const order = response.data;Considerations
- In this example, you perform bridging via a connected account for yourself, not for a third-party recipient. Therefore, both the originator and beneficiary use
"participantRelationshipType": "FirstParty", and no additional PII data is required. - The
quoteIdused in the order request is the same ID returned in the response from thePOST /trading/quotescall. - Since the source of this order is a Vault Account, once the provider receives the order request, a transfer will automatically be initiated from your Vault Account to the provider's connected account on Scrypt. This transfer is governed by the workspace's Transfer Policy, just like any other transfer in Fireblocks.
- ReQuote Option: Instead of
"type": "MARKET", you can use"type": "RETRY"withcount(1-10 retry attempts) and optionalslippageBps(slippage tolerance in basis points) to automatically retry quote generation if the original quote expires, giving you more control over price execution.
Order Tracking & Monitoring
After creating an order, monitor its execution status to track completion.
Polling for order status
// Get order status and details
const response = await fireblocks.trading.getOrder({
orderId: 'order_id_here',
});
const order = response.data;
// Check: order.status, order.executionSteps, order.createdAt, etc.Order Status Values
| Status | Description |
|---|---|
CREATED | Order has been created and is being processed |
AWAITING_PAYMENT | Waiting for payment to be received |
PENDING_USER_ACTION | Requires user action (e.g., approval in console) |
PROCESSING | Order is being executed |
COMPLETED | Order has been successfully completed |
FAILED | Order execution failed |
CANCELED | Order was canceled |
Note: FAILED, COMPLETED and CANCELED are terminal states.
Webhooks
Subscribe to order-update events through the Fireblocks Webhooks API. See the Fireblocks Webhooks API documentation for more details.
Additional Resources
- Trading API Overview
- Bridging via Direct Access Providers (DeFi) - For crypto-to-crypto bridging using direct access providers like Uniswap
- Fireblocks SDKs: Python | TypeScript | Java
- Fireblocks Developer Portal
Support
For questions or issues with the Trading API:
- Contact your Fireblocks Customer Success Manager
- Email: [email protected]
- Check the Fireblocks Developer Portal for updates
Updated 10 days ago