Sentra

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:

  1. Get Exchange Rate - Check current rates and fees
  2. Create Quote - Lock in a rate for a specific time period
  3. Create Off-Ramp Transfer - Initiate the transfer
  4. Send Crypto - User sends crypto to the provided address
  5. Complete Transfer - Provide transaction hash to complete
  6. 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

StatusDescription
AWAITING_FUNDSWaiting for crypto to be sent
PENDINGTransaction received, being verified
PROCESSINGCurrently being processed
SENTFunds released towards beneficiary account
COMPLETEDSuccessfully completed
FAILEDTransaction failed
EXPIREDTransfer expired
REFUNDEDFunds 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_key

Get All User Transfers

GET /payments/user/{userId}
X-API-KEY: sk_dev_your_api_key

Webhooks

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"]
}