On-Ramp, Off-Ramp, and Bridge/Swap via Account-Based Providers (CeFi)


📘

Beta Feature

The Trading API is currently in beta and subject to change. For participation details, contact your Fireblocks Customer Success Manager or email [email protected].

Fireblocks Trading API lets you perform on-ramp, off-ramp, and crypto swap/bridge operations through connected account-based providers. These flows allow you to convert between fiat and crypto or move liquidity across chains directly from your Fireblocks workspace. This guide shows how to discover available providers, get supported pairs and rates, create quotes, and submit executable orders. It also includes complete examples for DVP and prefunded settlement flows. Account-based providers 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 swap/bridging.

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/[email protected])
  • ✅ 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"
});

Setup

Before trading with account-based providers, you need to discover what providers are available and which accounts you have connected. If you haven't connected any accounts yet, see Fireblocks Connected Accounts for setup instructions.

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).


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

FieldDescription
idUnique identifier for the provider (use as providerId in subsequent API calls)
nameDisplay name of the provider
accountBasedtrue for account-based providers, false for direct access providers
connectedWhether you have at least one connected account with this provider
accountsArray 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"
});
const tradingPairs = response.data;

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.


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 atomically.

Settlement Type: DVP (Delivery vs Payment)
Execution Type: Market

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 move from outside Fireblocks. The order creation response includes 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

  • Because this example is a third-party payout, the beneficiary must include all PII required by the provider. The originator is the customer acting as a first party, so minimal originator data is required.
  • Since the settlement type is DVP and the source type is EXTERNAL, the funds move from outside Fireblocks. As a result, the order creation response includes 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 executes and settles 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": "ALFREDPAY",
        "accountId": "acc_5e9a2d1c4b7f3e8a"
      }
    ],
    "side": "BUY",
    "baseAssetId": "MXN",
    "baseAssetRail": "SPEI",
    "quoteAssetId": "USDC",
    "quoteAssetRail": "BLOCKCHAIN",
    "baseAmount": "500"
  },
  idempotencyKey: `quote-${Date.now()}`
});

const quote = quoteResponse.data.quotes[0];

In the quote response, you 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 are performing 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 quoteId used in the order request is the same ID returned in the response from the POST /trading/quotes call.

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 atomic delivery of both sides.

Settlement Type: DVP
Execution Type: Market

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 is automatically created from your vault to the provider. You 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: Crypto-to-Crypto Swap / Bridge - DVP Settlement with Quote Execution

Use Case: Execute a cross-chain bridge between blockchain networks 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",
    "baseAssetRail": "BLOCKCHAIN",
    "quoteAssetId": "TRX_USDT_S2UZ",
    "quoteAssetRail": "BLOCKCHAIN",
    "baseAmount": "15000"
  },
  idempotencyKey: `quote-${Date.now()}`
});

const quote = quoteResponse.data.quotes[0];

In the quote response, you 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 are performing 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 quoteId used in the order request is the same ID returned in the response from the POST /trading/quotes call.
  • Since the source of this order is a Vault Account, once the provider receives the order request, a transfer is automatically 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.

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

StatusDescription
CREATEDOrder has been created and is being processed
AWAITING_PAYMENTWaiting for payment to be received
PENDING_USER_ACTIONRequires user action (e.g., approval in console)
PROCESSINGOrder is being executed
COMPLETEDOrder has been successfully completed
FAILEDOrder execution failed
CANCELEDOrder was canceled

Webhooks

Subscribe to order-update events through the Fireblocks Webhooks API. See the Fireblocks Webhooks API documentation for more details.


Additional Resources


Support

For questions or issues with the Trading API: