Off-Ramp Flow (Crypto to Fiat)
Convert cryptocurrency (USDT/USDC) to Brazilian Real (BRL) and send funds via PIX
Overview
There are two ways to create off-ramp transactions:
- With Exchange Rate Quote - Lock in rates for price certainty
- Without Quote (Market Rate) - Use market rates at execution time
Method 1: With Exchange Rate Quote
This method provides rate certainty by locking in exchange rates before creating the transaction.
Flow Overview
Step 1: List Your Customers
First, retrieve the list of customers associated with your organization:
curl -X GET "https://api.sdigital2.com/v1/customers" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"Response:
{
"data": [
{
"id": "774f7a53-fd45-4634-9548-eb37c9554137",
"name": "John Doe",
"type": "INDIVIDUAL",
"createdAt": "2025-09-08T07:01:04.093Z",
"updatedAt": "2025-09-08T07:01:04.084Z"
}
],
"pagination": {
"page": 1,
"limit": 10
}
}Step 2: Get Customer Details and Balances
Get detailed information about a specific customer, including their wallet addresses and current balances:
curl -X GET "https://api.sdigital2.com/v1/customers/{customer_id}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"Response:
{
"id": "774f7a53-fd45-4634-9548-eb37c9554137",
"name": "John Doe",
"type": "INDIVIDUAL",
"createdAt": "2025-09-08T07:01:04.093Z",
"updatedAt": "2025-09-08T07:01:04.084Z",
"walletAddresses": [
{
"chain": "ARBITRUM",
"walletAddress": "0xebe39cfda54886b2db0d4e7e4c63a4ccbc880f84",
"balances": [
{
"currency": "USDC",
"amount": "0",
"updatedAt": "2025-09-12T22:56:00.648Z"
},
{
"currency": "USDT",
"amount": "0",
"updatedAt": "2025-09-12T22:56:00.648Z"
}
]
},
{
"chain": "BASE",
"walletAddress": "0x2fc4512d5859226cf0bf61fbbbdb5444fda60053",
"balances": [
{
"currency": "USDC",
"amount": "215.462157",
"updatedAt": "2025-09-12T22:56:00.566Z"
}
]
},
{
"chain": "ETHEREUM",
"walletAddress": "0xba1c64834804eac723776aa6addf216d307eb336",
"balances": [
{
"currency": "USDC",
"amount": "398.770344",
"updatedAt": "2025-09-12T22:56:00.648Z"
},
{
"currency": "USDT",
"amount": "0",
"updatedAt": "2025-09-12T22:56:00.648Z"
}
]
},
{
"chain": "POLYGON",
"walletAddress": "0xbc87a12b0e9570bb5472d6066f220db7e98b709e",
"balances": [
{
"currency": "USDC",
"amount": "0",
"updatedAt": "2025-09-12T22:56:00.594Z"
},
{
"currency": "USDT",
"amount": "0",
"updatedAt": "2025-09-12T22:56:00.594Z"
}
]
}
]
}Verify the customer has sufficient balance in the desired cryptocurrency before proceeding.
Step 3: Get Exchange Rate Quote
Request a locked exchange rate for the conversion. This ensures price certainty:
curl -X POST "https://api.sdigital2.com/v1/exchange-rates" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"chain": "ETHEREUM",
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"sourceCurrency": "USDC",
"sourceAmount": "100.00",
"destinationCurrency": "BRL",
"lockDuration": "30s"
}'Response:
{
"id": "faa8ee1b-a422-4ef0-bbd8-4e5c597bb218",
"sourceCurrency": "USDC",
"sourceAmount": "100.000000",
"destinationCurrency": "BRL",
"destinationAmount": "524.19",
"grossDestinationAmount": "535.16",
"baseExchangeRate": "5.351638",
"appliedExchangeRate": "5.241930",
"fees": {
"bps": "105",
"flatAmount": "1",
"totalAmount": "2.05",
"currency": "USDC"
},
"expiresAt": "2025-09-13T19:50:32.591Z"
}Exchange rate quotes expire! Use the expiresAt timestamp to ensure you
create the transaction before expiration.
Step 3: Create or Get Bank Account
Before creating an off-ramp transaction, you need a verified bank account. Create one if you don't have it:
curl -X POST "https://api.sdigital2.com/v1/bank-accounts" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"name": "Main Business Account",
"type": "EXTERNAL",
"rail": "PIX",
"currency": "BRL",
"beneficiary": {
"relationship": "SELF",
"legalName": "John Doe",
"taxId": "12345678900",
"email": "john.doe@example.com",
"incorporationDate": "2024-01-01",
"address": {
"line1": "123 Main Street",
"city": "São Paulo",
"state": "SP",
"postalCode": "01310-100",
"country": "BR"
}
},
"accountDetails": {
"keyType": "EMAIL",
"keyValue": "john.doe@example.com"
}
}'Response:
{
"id": "3190d115-987f-402f-b558-0316d3a22ebd",
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"name": "Main Business Account",
"type": "EXTERNAL",
"rail": "PIX",
"currency": "BRL",
"beneficiary": {
"relationship": "SELF",
"legalName": "John Doe",
"taxId": "12345678900",
"email": "john.doe@example.com",
"incorporationDate": "2024-01-01",
"address": {
"line1": "123 Main Street",
"city": "São Paulo",
"state": "SP",
"postalCode": "01310-100",
"country": "BR"
}
},
"accountDetails": {
"keyType": "EMAIL",
"keyValue": "john.doe@example.com"
},
"verification": {
"status": "APPROVED",
"level": "BASIC"
},
"createdAt": "2025-09-13T10:00:00.000Z",
"updatedAt": "2025-09-13T10:00:00.000Z"
}Important: Ensure the bank account is verified (status: APPROVED) before using it in transactions. Monitor the verification status and wait for approval.
Step 4: Create Transaction with Quote
Create the transaction using the exchange rate quote and bank account ID:
curl -X POST "https://api.sdigital2.com/v1/transactions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"exchangeRateId": "faa8ee1b-a422-4ef0-bbd8-4e5c597bb218",
"source": {
"paymentRail": "ETHEREUM"
},
"destination": {
"bankAccountId": "3190d115-987f-402f-b558-0316d3a22ebd"
},
"purpose": "TRADE_TRANSACTIONS"
}'Response:
{
"id": "82c1bfb7-ef1e-42e3-94d3-8c8b7677b14d",
"type": "OFF_RAMP",
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"sourceAmount": "100",
"source": {
"currency": "USDC",
"paymentRail": "ETHEREUM"
},
"destination": {
"currency": "BRL",
"paymentRail": "PIX"
},
"purpose": "TRADE_TRANSACTIONS",
"createdAt": "2025-09-13T19:50:34.847Z",
"updatedAt": "2025-09-13T19:50:34.827Z",
"status": "TRANSFERRING_STABLECOIN"
}Step 5: Monitor Transaction Status
Check the transaction status periodically:
curl -X GET "https://api.sdigital2.com/v1/transactions/{transaction_id}" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json"Completed Transaction Response:
{
"id": "82c1bfb7-ef1e-42e3-94d3-8c8b7677b14d",
"type": "OFF_RAMP",
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"sourceAmount": "100",
"source": {
"currency": "USDC",
"paymentRail": "ETHEREUM"
},
"destination": {
"currency": "BRL",
"paymentRail": "PIX"
},
"purpose": "TRADE_TRANSACTIONS",
"createdAt": "2025-09-13T19:50:34.847Z",
"updatedAt": "2025-09-13T19:50:34.827Z",
"status": "SUCCESS",
"receipt": {
"sourceCurrency": "USDC",
"sourceAmount": "100.000000",
"destinationCurrency": "BRL",
"destinationAmount": "524.19",
"grossDestinationAmount": "535.16",
"baseExchangeRate": "5.351638",
"appliedExchangeRate": "5.241930",
"fees": {
"bps": "105",
"flatAmount": "1",
"totalAmount": "2.05",
"currency": "USDC"
}
}
}The transaction will automatically process once the customer's USDC balance is sufficient and the conversion will be sent to their PIX account.
Method 2: Without Exchange Rate Quote (Market Rate)
This method uses market rates at execution time, requiring fewer API calls but without rate guarantees.
Flow Overview
Steps 1-3: List Customers, Check Balances, and Get Bank Account
Follow the same steps as Method 1 to list customers, check their balances, and ensure you have a verified bank account.
Step 4: Create Transaction with Market Rate
Create the transaction directly without an exchange rate quote. You'll need to specify additional fields:
curl -X POST "https://api.sdigital2.com/v1/transactions" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"sourceAmount": "100",
"source": {
"paymentRail": "ETHEREUM",
"currency": "USDC"
},
"destination": {
"bankAccountId": "3190d115-987f-402f-b558-0316d3a22ebd"
},
"purpose": "TRADE_TRANSACTIONS"
}'Key Differences from Method 1:
- No
exchangeRateIdfield - Must specify
sourceAmountfield - Must specify
currencyin thesourceobject - Destination uses
bankAccountIdinstead of payment rail details - Exchange rate is determined at execution time
Response:
{
"id": "82c1bfb7-ef1e-42e3-94d3-8c8b7677b14d",
"type": "OFF_RAMP",
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"sourceAmount": "100",
"source": {
"currency": "USDC",
"paymentRail": "ETHEREUM"
},
"destination": {
"currency": "BRL",
"paymentRail": "PIX"
},
"purpose": "TRADE_TRANSACTIONS",
"createdAt": "2025-09-13T19:50:34.847Z",
"updatedAt": "2025-09-13T19:50:34.827Z",
"status": "TRANSFERRING_STABLECOIN"
}Step 4: Monitor Transaction Status
Monitor the transaction status the same way as Method 1. The final receipt will include the actual exchange rate that was applied:
{
"id": "82c1bfb7-ef1e-42e3-94d3-8c8b7677b14d",
"type": "OFF_RAMP",
"customerId": "774f7a53-fd45-4634-9548-eb37c9554137",
"sourceAmount": "100",
"source": {
"currency": "USDC",
"paymentRail": "ETHEREUM"
},
"destination": {
"currency": "BRL",
"paymentRail": "PIX"
},
"purpose": "TRADE_TRANSACTIONS",
"createdAt": "2025-09-13T19:50:34.847Z",
"updatedAt": "2025-09-13T19:50:34.827Z",
"status": "SUCCESS",
"receipt": {
"sourceCurrency": "USDC",
"sourceAmount": "100.000000",
"destinationCurrency": "BRL",
"destinationAmount": "524.19",
"grossDestinationAmount": "535.16",
"baseExchangeRate": "5.351638",
"appliedExchangeRate": "5.241930",
"fees": {
"bps": "105",
"flatAmount": "1",
"totalAmount": "2.05",
"currency": "USDC"
}
}
}Market Rate Considerations:
- Exchange rates fluctuate in real-time
- Final amounts may differ from estimates
- Best for users who prioritize simplicity over rate certainty
- Consider showing rate estimates in your UI before confirmation
Choosing the Right Method
Use Method 1 (With Quote) when:
- Users need price certainty before confirming
- Building trading or financial applications
- Handling large transaction amounts
- Users are price-sensitive
Use Method 2 (Market Rate) when:
- Building simple conversion tools
- Users prioritize speed over precision
- Handling smaller transaction amounts
- Rate fluctuations are acceptable