Get Payout Preview (Phase 2a)
Before submitting a sell payout, call this endpoint to discover which beneficiary fields are required for the destination currency and country. The response contains dynamic form field definitions that your frontend should render for the customer to fill in.
https://api.zenpayz.com/payment/api/v1/off-ramp/sell/payout-previewRequest
Headers
| Header | Description |
|---|---|
x-request-id OPTIONAL | Custom request ID for tracing |
This endpoint does not require authentication headers.
Query Parameters
| Parameter | Type | Description |
|---|---|---|
intentId REQUIRED | string— | Ramp intent ID |
fiatCurrency REQUIRED | string— | Target fiat currency (e.g. USD) |
country OPTIONAL | stringUS | ISO country code for the payout destination |
payoutType OPTIONAL | stringbank_transfer | Payout method |
The crypto deposit for this intent must be in confirmed or matched status. If the deposit hasn't been confirmed yet, this endpoint returns a 400 error.
Response
Success (200 OK)
{
"success": true,
"data": {
"selectedTsp": "zenpay_routing",
"tspDisplayName": "ZenPays",
"requiredFields": [
{
"fieldName": "receiverFirstName",
"label": "First Name",
"type": "text",
"required": true,
"placeholder": "Enter first name"
},
{
"fieldName": "receiverLastName",
"label": "Last Name",
"type": "text",
"required": true,
"placeholder": "Enter last name"
},
{
"fieldName": "receiverAccountNumber",
"label": "Account Number",
"type": "text",
"required": true,
"placeholder": "Enter account number"
},
{
"fieldName": "receiverCountry",
"label": "Country",
"type": "text",
"required": true,
"placeholder": "ISO country code (e.g. US)"
},
{
"fieldName": "receiverBankName",
"label": "Bank Name",
"type": "text",
"required": true,
"placeholder": "Enter bank name"
}
],
"optionalFields": [
{
"fieldName": "receiverEmail",
"label": "Email",
"type": "email",
"required": false,
"placeholder": "Enter email address"
},
{
"fieldName": "receiverPhone",
"label": "Phone",
"type": "tel",
"required": false,
"placeholder": "Enter phone number"
}
],
"oneOfGroups": [
["receiverBankCode", "receiverBankName"]
],
"fiatAmount": 19.78,
"fiatCurrency": "USD",
"fees": {
"platform": 0.62,
"network": 0,
"total": 0.62
}
},
"message": "Payout preview retrieved"
}
Response Fields
| Parameter | Type | Description |
|---|---|---|
selectedTsp OPTIONAL | string | Selected payout provider |
tspDisplayName OPTIONAL | string | Human-readable provider name |
requiredFields OPTIONAL | array | Fields that must be provided |
optionalFields OPTIONAL | array | Fields that can optionally be provided |
oneOfGroups OPTIONAL | array| null | Groups where at least one field must be filled |
fiatAmount OPTIONAL | number | Calculated fiat payout amount |
fiatCurrency OPTIONAL | string | Fiat currency |
fees OPTIONAL | object | Fee breakdown |
Field Definition Object
| Parameter | Type | Description |
|---|---|---|
fieldName OPTIONAL | string | Key to use in beneficiaryDetails when submitting payout |
label OPTIONAL | string | Human-readable label for the form field |
type OPTIONAL | string | Input type: text, email, tel, number, or select |
required OPTIONAL | boolean | Whether the field is mandatory |
placeholder OPTIONAL | string | Placeholder text |
pattern OPTIONAL | string| null | Regex validation pattern |
validationMessage OPTIONAL | string| null | Error message for failed validation |
options OPTIONAL | array| null | Options for select type fields |
minLength OPTIONAL | number| null | Minimum character length |
maxLength OPTIONAL | number| null | Maximum character length |
Fees Object
| Parameter | Type | Description |
|---|---|---|
platform OPTIONAL | number | Platform fee |
network OPTIONAL | number | Network/gas fee |
total OPTIONAL | number | Total fees |
Use the requiredFields and optionalFields arrays to dynamically build your payout form. Each field includes validation constraints (pattern, minLength, maxLength) so you can validate client-side before submitting.
For oneOfGroups, at least one field from each group must be provided. For example, ["receiverBankCode", "receiverBankName"] means you need either the SWIFT/BIC code or the bank name.
Error Responses
| Code | HTTP | Message |
|---|---|---|
| BAD_REQUEST | 400 | Deposit not yet confirmed, or invalid intent |
| NOT_FOUND | 404 | Intent not found |
| SELL_PAYOUT_PREVIEW_FAILED | 500 | Failed to generate preview |
Examples
- cURL
- JavaScript
- Python
curl "https://api.zenpayz.com/payment/api/v1/off-ramp/sell/payout-preview?intentId=ri_1710345678000_a1b2c3d4e5f6g7h8&fiatCurrency=USD&country=US"
const params = new URLSearchParams({
intentId: 'ri_1710345678000_a1b2c3d4e5f6g7h8',
fiatCurrency: 'USD',
country: 'US',
});
const response = await fetch(
`https://api.zenpayz.com/payment/api/v1/off-ramp/sell/payout-preview?${params}`
);
const { data } = await response.json();
console.log(`Provider: ${data.tspDisplayName}`);
console.log(`Payout: ${data.fiatAmount} ${data.fiatCurrency}`);
console.log(`Fees: ${data.fees.total}`);
// Dynamically render form fields
data.requiredFields.forEach((field) => {
const input = document.createElement('input');
input.name = field.fieldName;
input.placeholder = field.placeholder;
input.type = field.type;
input.required = field.required;
if (field.pattern) input.pattern = field.pattern;
document.getElementById('payout-form').appendChild(input);
});
import requests
response = requests.get(
"https://api.zenpayz.com/payment/api/v1/off-ramp/sell/payout-preview",
params={
"intentId": "ri_1710345678000_a1b2c3d4e5f6g7h8",
"fiatCurrency": "USD",
"country": "US",
},
)
data = response.json()["data"]
print(f"Provider: {data['tspDisplayName']}")
print(f"Payout: {data['fiatAmount']} {data['fiatCurrency']}")
print(f"Fees: {data['fees']['total']}")
print("\nRequired fields:")
for field in data["requiredFields"]:
print(f" - {field['label']} ({field['fieldName']}): {field['type']}")
Next Steps
- Submit Sell Payout — Submit beneficiary details and trigger payout (Phase 2b)
- Create Sell Deposit — Generate deposit address (Phase 1)
- Off-Ramp Flow — Complete sell integration guide