Sandbox: fund your sandbox prepaid account
x-idempotency-key
Moves funds · Increases merchant prepaid available balance; the counterparty is custody.settled.
See the response table below for failure handling. Retry timeouts (504) with the same idempotency key — we may already have processed the request; use a new key after a business failure; the same key replays that failure.
Available only in the sandbox. Live credentials return 404, not 403, because this capability must not exist in production. The check is whether the merchant resolved from the token is a shadow entity, not the hostname being called.
It uses the exact production posting path, exercising funding gates, queues, low-balance thresholds, and ledger invariants. An endpoint that simply changed a balance could not verify those.
The input amount and output credited are decimal strings, such as "500.000000", unlike the fixed-point integer strings in /v1/merchant/balances. The default credit is 10000 whole units of the asset; the maximum per request is 1,000,000 units. An endpoint allowing a credit of 10^30 at once would produce limit behavior unlike production.
Idempotency: reusing the same x-idempotency-key returns the same credit with duplicated: true. In that case no new posting occurs; do not count it as another credit.
Prerequisites
- The current token resolves to a sandbox shadow entity; live credentials always return 404.
- The asset exists in
assetsand is enabled.
Request Headers
| Field | Type | Required | Description |
|---|---|---|---|
x-idempotency-key |
string | Required | UUID v4. Missing returns idempotency_key_required; an invalid format returns
idempotency_key_invalid; the same key with a different body returns idempotency_key_reused. |
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
asset |
string | Required | Asset code, case-insensitive; the server converts it to uppercase. Unrecognized values return asset_not_allowed. |
amount |
string | Optional | Amount to credit, a decimal string. Decimal places must not exceed the asset's
ledger_scale, except that excess trailing digits are accepted if all are 0.
Defaults to 10000 whole units if omitted. Must be positive.USDT(scale 6):"500.000000" |
Response
duplicated: true means an idempotency hit, with no new posting on this call.{
"ok": true,
"asset": "USDT",
"credited": "500.000000",
"ledger_scale": 6,
"journal_id": "jrn_01J8Z6M2K9QF3H7V0"
}invalid_request: body is not JSON, asset missing, or amount invalid/nonpositive.
asset_not_allowed: asset is not in the catalog or is disabled.
limit_exceeded: more than 1,000,000 whole units in one request; includes limit_type: single.idempotency_key_reused: same key with a different body.
idempotency_in_progress: the original request is still being processed.curl -X POST 'https://api.zinfra.vip/v1/sandbox/faucet' \
-H 'x-auth-token: Bearer $TOKEN' \
-H 'x-idempotency-key: $IDEMPOTENCY_KEY' \
-H 'content-type: application/json' \
-d '{
"asset": "USDT",
"amount": "500.000000"
}'const res = await fetch("https://api.zinfra.vip/v1/sandbox/faucet", {
method: "POST",
headers: {
"x-auth-token": "Bearer $TOKEN",
"x-idempotency-key": "$IDEMPOTENCY_KEY",
"content-type": "application/json",
},
body: JSON.stringify({
"asset": "USDT",
"amount": "500.000000"
}),
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();import requests
res = requests.post(
"https://api.zinfra.vip/v1/sandbox/faucet",
headers={
"x-auth-token": "Bearer $TOKEN",
"x-idempotency-key": "$IDEMPOTENCY_KEY",
"content-type": "application/json",
},
json={
"asset": "USDT",
"amount": "500.000000"
},
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()req, _ := http.NewRequest("POST", "https://api.zinfra.vip/v1/sandbox/faucet",
strings.NewReader(`{
"asset": "USDT",
"amount": "500.000000"
}`))
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-idempotency-key", "$IDEMPOTENCY_KEY")
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/sandbox/faucet"))
.header("x-auth-token", "Bearer $TOKEN")
.header("x-idempotency-key", "$IDEMPOTENCY_KEY")
.header("content-type", "application/json")
.method("POST", HttpRequest.BodyPublishers.ofString("""
{
"asset": "USDT",
"amount": "500.000000"
}
"""))
.build();
// Use String / BigDecimal for amounts, not double.$ch = curl_init('https://api.zinfra.vip/v1/sandbox/faucet');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'POST',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'x-auth-token: Bearer $TOKEN',
'x-idempotency-key: $IDEMPOTENCY_KEY',
'content-type: application/json',
],
CURLOPT_POSTFIELDS => <<<'JSON'
{
"asset": "USDT",
"amount": "500.000000"
}
JSON,
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
{
"ok": true,
"asset": "USDT",
"credited": "500.000000",
"ledger_scale": 6,
"journal_id": "jrn_01J8Z6M2K9QF3H7V0"
}