Create Sell Deposit (Phase 1)
Phase 1 of the two-phase off-ramp (sell) flow. Generates a crypto deposit address where the customer sends their crypto. The system monitors the address for incoming deposits and confirms receipt automatically.
This endpoint is idempotent — calling it again with the same intentId returns the existing deposit instead of creating a new one.
POST
https://api.zenpayz.com/payment/api/v1/off-ramp/sell/checkoutBearer · API key
Request
Headers
| Header | Description |
|---|---|
Content-Type REQUIRED | application/json |
x-request-id OPTIONAL | Custom request ID for tracing |
Public Endpoint
This endpoint does not require authentication headers. It is designed to be called from your checkout or widget page.
Body Parameters
| Parameter | Type | Description |
|---|---|---|
intentId REQUIRED | string | Ramp intent ID (from Create Ramp Intent) |
cryptoCurrency REQUIRED | string | Crypto to deposit (e.g. USDT) |
chain REQUIRED | string | Blockchain network (e.g. tron, ethereum) |
fiatCurrency REQUIRED | string | Target fiat currency (e.g. USD) |
cryptoAmount REQUIRED | number | Amount of crypto to send |
fiatAmount REQUIRED | number | Expected fiat payout (from quote) |
rate REQUIRED | number | Locked exchange rate (from quote) |
totalFee REQUIRED | number | Total fees (from quote) |
quoteId OPTIONAL | string | Reference to the quote used |
onramp OPTIONAL | string | Quote provider identifier |
Use Quote Values
Pass the rate, fiatAmount, and totalFee directly from a Sell Quote response to ensure consistent pricing.
Response
Success (200 OK)
{
"success": true,
"data": {
"intentId": "ri_1710345678000_a1b2c3d4e5f6g7h8",
"depositAddress": "TLfMkVBKQSy7gzP7x9URJp6ZLXyWGZbwDs",
"memo": null,
"currency": "USDT",
"chain": "tron",
"expectedCryptoAmount": 20,
"fiatAmount": 19.78,
"fiatCurrency": "USD",
"rate": 0.999,
"cryptoDepositId": "d4e5f6a7-b8c9-1234-5678-abcdef012345",
"expiresAt": "2026-03-15T10:00:00.000Z",
},
"message": "Sell checkout created"
}
Response Fields
| Parameter | Type | Description |
|---|---|---|
intentId OPTIONAL | string | The ramp intent ID |
depositAddress OPTIONAL | string | Crypto address to send funds to |
memo OPTIONAL | string| null | Memo/tag (required for XRP, XLM, etc.) |
currency OPTIONAL | string | Crypto currency (e.g. USDT) |
chain OPTIONAL | string | Blockchain network |
expectedCryptoAmount OPTIONAL | number | Amount the customer should send |
fiatAmount OPTIONAL | number | Expected fiat payout |
fiatCurrency OPTIONAL | string | Fiat currency code |
rate OPTIONAL | number | Locked exchange rate |
cryptoDepositId OPTIONAL | string | Deposit tracking ID (needed for Phase 2) |
expiresAt OPTIONAL | string | Deposit expiry timestamp |
Save the cryptoDepositId
You will need cryptoDepositId when submitting the payout in Phase 2. Store it alongside the intentId.
Error Responses
| Code | HTTP | Message |
|---|---|---|
| BAD_REQUEST | 400 | Invalid or inactive intent |
| SELL_CHECKOUT_FAILED | 500 | Failed to generate deposit address |
Examples
- cURL
- JavaScript
- Python
curl -X POST https://api.zenpayz.com/payment/api/v1/off-ramp/sell/checkout \
-H "Content-Type: application/json" \
-d '{
"intentId": "ri_1710345678000_a1b2c3d4e5f6g7h8",
"cryptoCurrency": "USDT",
"chain": "tron",
"fiatCurrency": "USD",
"cryptoAmount": 20,
"fiatAmount": 19.78,
"rate": 0.999,
"totalFee": 0.62
}'
const response = await fetch(
'https://api.zenpayz.com/payment/api/v1/off-ramp/sell/checkout',
{
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
intentId: 'ri_1710345678000_a1b2c3d4e5f6g7h8',
cryptoCurrency: 'USDT',
chain: 'tron',
fiatCurrency: 'USD',
cryptoAmount: 20,
fiatAmount: 19.78,
rate: 0.999,
totalFee: 0.62,
}),
}
);
const { data } = await response.json();
console.log(`Send ${data.expectedCryptoAmount} ${data.currency} to:`);
console.log(`Address: ${data.depositAddress}`);
if (data.memo) console.log(`Memo: ${data.memo}`);
console.log(`Chain: ${data.chain}`);
console.log(`Deposit ID: ${data.cryptoDepositId}`);
// Display to customer with QR code, countdown timer, etc.
import requests
response = requests.post(
"https://api.zenpayz.com/payment/api/v1/off-ramp/sell/checkout",
json={
"intentId": "ri_1710345678000_a1b2c3d4e5f6g7h8",
"cryptoCurrency": "USDT",
"chain": "tron",
"fiatCurrency": "USD",
"cryptoAmount": 20,
"fiatAmount": 19.78,
"rate": 0.999,
"totalFee": 0.62,
},
)
data = response.json()["data"]
print(f"Send {data['expectedCryptoAmount']} {data['currency']} to:")
print(f"Address: {data['depositAddress']}")
print(f"Chain: {data['chain']}")
print(f"Deposit ID: {data['cryptoDepositId']}")
Two-Phase Sell Flow
Phase 1 (this endpoint) Phase 2
┌──────────────────────┐ ┌──────────────────────┐
│ POST sell/checkout │ │ GET payout-preview │
│ → deposit address │ │ → required fields │
│ │ │ │
│ Customer sends crypto│ ──► │ POST sell/payout │
│ System confirms │ │ → fiat transfer │
└──────────────────────┘ └──────────────────────┘
Next Steps
- Get Payout Preview — Discover required beneficiary fields (Phase 2a)
- Submit Sell Payout — Execute the fiat payout (Phase 2b)
- Off-Ramp Flow — Complete sell integration guide