Z Zise Developers 简体中文

Remittance estimate: no order or fund hold; read applied_rate

POST /v1/remit/quotes scope: remittances:read
On behalf of a member · x-on-behalf-of required

No order, fund hold, database write, or idempotency key. This is read-only calculation, safe to call repeatedly as users enter values.

Choose exactly one direction:

  • Supply payout_amount, what the recipient receives, to calculate customer_total.
  • Supply source_amount, what the sender spends, to reverse-calculate payout_amount, ensuring a forward calculation of customer_total is ≤ that budget. Each step rounds down; rounding the other way would debit more than authorized.

Both or neither amounts produce 400; silently preferring one would make the other appear ignored.

Prerequisites

  • This line is enabled for you and its settlement currency is configured
  • Source asset enabled and spendable, with a fixed-value anchor
  • Payee belongs to this member
FieldTypeRequiredDescription
x-on-behalf-of string Required Member on whose behalf the call is made; fees and limits are member-scoped.

Request Body

FieldTypeRequiredDescription
payee_id string Required Payee ID. Optional pye_ prefix; the remaining value must contain digits only.
line "express" | "pobo" Optional Product line: express uses the platform as payer; pobo uses the member’s own upstream subaccount for personal remittance. Defaults to express; unknown values silently fall back to express.
asset string Optional Asset to debit. Defaults to USDT.
payout_amount string Optional Recipient amount in the destination currency. Mutually exclusive with source_amount. Precision depends on the currency; an extra decimal place is rejected by upstream format validation.GBP uses 2 decimals: "380.00"; JPY uses 0: "50000"
source_amount string Optional Maximum amount this member will spend in the source asset. Mutually exclusive with payout_amount. Fixed-point string with precision equal to the asset’s ledger_scale.USDT uses 6 decimals: "500.000000"

Response

200Estimate. Another 200 case exists: rate_available: false + reason, as described above. Only fee_bps / fee_fixed / source_asset are usable then.
{
  "rate_available": true,
  "line": "express",
  "source_asset": "USDT",
  "payout_currency": "GBP",
  "payout_amount": "380.00",
  "source_amount": "",
  "payer_name": "",
  "customer_total": "499.980000",
  "below_min": false,
  "min_amount": "10.000000",
  "fee": "2.480000",
  "fee_bps": 50,
  "fee_fixed": "1.000000",
  "indicative_rate": "1.2899",
  "applied_rate": "1.2743",
  "slippage": {
    "default_bps": 100,
    "min_bps": 50,
    "max_bps": 1000
  }
}
400invalid_request: both amounts supplied, neither supplied, nonnumeric payee_id, or invalid JSON. resource_not_found: payee not associated with this member. product_not_available: line not enabled for you or source asset unavailable. invalid_fields: amount cannot be parsed, such as precision beyond ledger scale.

Additional Details

Read both: indicative_rate and applied_rate differ

indicative_rate is the upstream’s current indicative price; applied_rate is the rate actually used to calculate the payout, after a conservative adjustment. Using only the former makes your displayed numbers unable to reproduce the payout. Testing on 2026-08-10 measured a 2.37% difference, absent from any fee item. Display applied_rate and retain indicative_rate for review.

Neither is an execution price. That is determined at dispatch within the user’s slippage limit.

Unavailable rates return 200, not 5xx

rate_available: false + reason explains the issue. Fees are still returned because they are locally calculable. Mark the rate unavailable and render the rest; hiding everything suggests the whole feature is broken. The three reason values require different handling:

  • remit_settlement_unconfigured: our configuration issue; waiting does not help the user.
  • remit_rate_unavailable: temporary upstream unavailability; retrying later is meaningful.
  • remit_amount_too_small, accompanied by amount_too_small: true: changing the amount resolves it. Do not present it as “try again later”.

We determine below_min; do not compare it again yourself

Although you have min_amount, the actual criterion uses the payout grid, which you cannot reproduce without the fee, discount, and anchor rate. A local comparison can block a user entering 10 USDT against a minimum of 10, because round-trip quantization yields customer_total of 9.999115.

⚠ Unrecognized line values silently fall back to express, without error. ⚠ Responses echo line / source_asset / source_amount unchanged. Use them to identify whether the response matches the current input; arrival order need not match request order. For reverse calculation, there is no other discriminator.

Request
curl -X POST 'https://api.zinfra.vip/v1/remit/quotes' \
  -H 'x-auth-token: Bearer $TOKEN' \
  -H 'x-on-behalf-of: $MEMBER_ID' \
  -H 'content-type: application/json' \
  -d '{
    "payee_id": "pye_1042",
    "line": "express",
    "asset": "USDT",
    "payout_amount": "380.00"
  }'
const res = await fetch("https://api.zinfra.vip/v1/remit/quotes", {
  method: "POST",
  headers: {
    "x-auth-token": "Bearer $TOKEN",
    "x-on-behalf-of": "$MEMBER_ID",
    "content-type": "application/json",
  },
  body: JSON.stringify({
    "payee_id": "pye_1042",
    "line": "express",
    "asset": "USDT",
    "payout_amount": "380.00"
  }),
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();
import requests

res = requests.post(
    "https://api.zinfra.vip/v1/remit/quotes",
    headers={
        "x-auth-token": "Bearer $TOKEN",
        "x-on-behalf-of": "$MEMBER_ID",
        "content-type": "application/json",
    },
    json={
      "payee_id": "pye_1042",
      "line": "express",
      "asset": "USDT",
      "payout_amount": "380.00"
    },
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()
req, _ := http.NewRequest("POST", "https://api.zinfra.vip/v1/remit/quotes",
    strings.NewReader(`{
  "payee_id": "pye_1042",
  "line": "express",
  "asset": "USDT",
  "payout_amount": "380.00"
}`))
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
req.Header.Set("content-type", "application/json")
res, err := http.DefaultClient.Do(req)
// Decode amount fields as string, not float64.
HttpRequest req = HttpRequest.newBuilder()
    .uri(URI.create("https://api.zinfra.vip/v1/remit/quotes"))
    .header("x-auth-token", "Bearer $TOKEN")
    .header("x-on-behalf-of", "$MEMBER_ID")
    .header("content-type", "application/json")
    .method("POST", HttpRequest.BodyPublishers.ofString("""
{
  "payee_id": "pye_1042",
  "line": "express",
  "asset": "USDT",
  "payout_amount": "380.00"
}
"""))
    .build();
// Use String / BigDecimal for amounts, not double.
$ch = curl_init('https://api.zinfra.vip/v1/remit/quotes');
curl_setopt_array($ch, [
  CURLOPT_CUSTOMREQUEST => 'POST',
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => [
    'x-auth-token: Bearer $TOKEN',
    'x-on-behalf-of: $MEMBER_ID',
    'content-type: application/json',
  ],
  CURLOPT_POSTFIELDS => <<<'JSON'
{
  "payee_id": "pye_1042",
  "line": "express",
  "asset": "USDT",
  "payout_amount": "380.00"
}
JSON,
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
200
{
  "rate_available": true,
  "line": "express",
  "source_asset": "USDT",
  "payout_currency": "GBP",
  "payout_amount": "380.00",
  "source_amount": "",
  "payer_name": "",
  "customer_total": "499.980000",
  "below_min": false,
  "min_amount": "10.000000",
  "fee": "2.480000",
  "fee_bps": 50,
  "fee_fixed": "1.000000",
  "indicative_rate": "1.2899",
  "applied_rate": "1.2743",
  "slippage": {
    "default_bps": 100,
    "min_bps": 50,
    "max_bps": 1000
  }
}