Off-Ramp Payments
Convert crypto to fiat with Sentra's off-ramp API
Overview
Off-ramp payments allow you to convert cryptocurrency to fiat currency and receive it in a specified bank accounts.
Off-Ramp Flow
The off-ramp process follows these steps:
- Get Exchange Rate - Check current rates and fees
- Create Quote - Lock in a rate for a specific time period
- Create Off-Ramp Transfer - Initiate the transfer
- Send Crypto - User sends crypto to the provided address
- Complete Transfer - Provide transaction hash to complete
- Receive Fiat - Fiat is deposited to the bank account
Step 1: Get Exchange Rate
Before creating a quote, check the current exchange rate and fees:
POST /payments/{userId}/rate
Content-Type: application/json
X-API-KEY: sk_dev_your_api_key
{
"source": {
"currency": "USDC",
"amount": 1000,
"rail": "POLYGON"
},
"destination": {
"currency": "USD",
"rail": "ACH",
"countryCode": "US"
},
"developerVariableFee": 0.005
}Response
{
"sourceCurrency": "USDC",
"sourceAmount": 1000,
"sourceRail": "POLYGON",
"destinationCurrency": "USD",
"destinationAmount": 994.5,
"destinationRail": "ACH",
"destinationCountryCode": "US",
"exchangeRate": 1.0,
"fee": 5.5
}Step 2: Create Quote
Lock in the exchange rate by creating a quote:
POST /payments/{userId}/quote
Content-Type: application/json
X-API-KEY: sk_dev_your_api_key
{
"source": {
"currency": "USDC",
"amount": 1000,
"rail": "POLYGON"
},
"destination": {
"currency": "USD",
"rail": "ACH",
"countryCode": "US",
"paymentAccountId": "bank_account_id_here"
},
"developerVariableFee": 0.005
}Response
{
"id": "550e8400-...",
"sourceCurrency": "USDC",
"sourceAmount": 1000,
"sourceRail": "POLYGON",
"destinationCurrency": "USD",
"destinationAmount": 994.5,
"destinationRail": "ACH",
"destinationCountryCode": "US",
"exchangeRate": 1.0,
"totalFee": 5.5,
"expiresAt": "2024-01-15T10:45:00Z",
"createdAt": "2024-01-15T10:30:00Z"
}Quotes typically expire after 10-15 minutes. You must create the transfer before the quote expires.
Step 3: Create Off-Ramp Transfer
Initiate the off-ramp transfer using your quote:
POST /payments/recipient/{recipientId}/off-ramp
Content-Type: application/json
X-API-KEY: sk_dev_your_api_key
{
"idempotencyKey": "unique-transfer-id-12345",
"quoteId": "550e8400-...",
"bankAccountId": "bank_account_id_here",
"fromAddress": "0x7434...5238",
"paymentReason": "TRANSFER_TO_SELF",
"documentReference": "Invoice-2024-001",
"files": [
"data:application/pdf;name=..."
]
}Response
{
"id": "550e8400-...",
"idempotencyKey": "unique-transfer-id-12345",
"type": "OFF_RAMP",
"status": "AWAITING_FUNDS",
"quoteId": "550e8400-...",
"bankAccountId": "bank_account_id_here",
"walletId": null,
"transactionHash": null,
"fee": 5.5,
"reason": null,
"depositAddress": "0x1234...5678",
"depositAmount": 1000,
"depositChain": "POLYGON",
"createdAt": "2024-01-15T10:30:00Z",
"expiresAt": "2024-01-15T11:30:00Z"
}Step 4: Complete the Transfer
After sending crypto to the deposit address, provide the transaction hash:
POST /payments/recipient/{recipientId}/off-ramp/{paymentId}/complete
Content-Type: application/json
X-API-KEY: sk_dev_your_api_key
{
"transactionHash": "0xabcdef123456789..."
}Response
{
"id": "550e8400-...",
"status": "PROCESSING",
"transactionHash": "0xabcdef123456789...",
"sentAt": "2024-01-15T10:35:00Z"
}Transaction Statuses
| Status | Description |
|---|---|
AWAITING_FUNDS | Waiting for crypto to be sent |
PENDING | Transaction received, being verified |
PROCESSING | Currently being processed |
SENT | Funds released towards beneficiary account |
COMPLETED | Successfully completed |
FAILED | Transaction failed |
EXPIRED | Transfer expired |
REFUNDED | Funds returned to sender |
Idempotency
Always use a unique idempotencyKey for each transfer request. This prevents duplicate transfers if you need to retry the request:
const idempotencyKey = `transfer-${userId}-${Date.now()}`;Monitoring Transfers
Get Transfer Status
GET /payments/{id}
X-API-KEY: sk_dev_your_api_keyGet All User Transfers
GET /payments/user/{userId}
X-API-KEY: sk_dev_your_api_keyWebhooks
Set up webhooks to receive real-time updates when transfer statuses change:
POST /webhooks
Content-Type: application/json
X-API-KEY: sk_dev_your_api_key
{
"url": "https://your-app.com/webhooks/sentra",
"secret": "your_webhook_secret",
"events": ["payment.updated"]
}