Цей контент ще не доступний вашою мовою.
CoinsSend does not use one universal error envelope and does not guarantee a
symbolic code field. Branch on HTTP status first, then parse the applicable
documented shape.
Success Envelope
Section titled “Success Envelope”Most successful operations return:
{ "data": {}, "status": "success"}Successful write operations currently return HTTP 200, including asynchronous
withdrawal submission.
Error Shapes
Section titled “Error Shapes”Authentication Errors
Section titled “Authentication Errors”Header authentication failures return only error:
{ "error": "Invalid sign"}Verified messages include Missing headers, Missing timestamp,
Invalid merchant, Invalid sign, Timestamp expired, and
Merchant account is suspended.
Endpoint Errors
Section titled “Endpoint Errors”Endpoint failures normally return:
{ "status": "error", "message": "Order id already exists"}Some endpoints add fields at the top level. Provider-card failures add
failure_code; withdrawal failures can add amounts and fee details. Treat
human-readable message text as descriptive rather than a stable machine code.
Validation
Section titled “Validation”Validation failures use HTTP 422:
{ "errors": { "amount": [ "The amount field is required." ] }, "status": "error", "message": "The given data was invalid."}Rate Limiting
Section titled “Rate Limiting”The wallet-creation limit returns status and message. Other HTTP 429
responses may use a different shape or include retry_after and a
Retry-After header. Treat rate-limit metadata as optional; see
Rate Limits and Safe Retries.
HTTP Statuses
Section titled “HTTP Statuses”| Status | Meaning in the public contract |
|---|---|
400 | Missing auth input or an endpoint rejection. Withdrawal permission denial currently uses this status. |
401 | Invalid merchant/signature or expired timestamp. |
403 | Suspended/blocked merchant state or authorization failure. |
404 | Public invoice or QR resource not found. |
409 | Invoice order_id already exists, or wallet creation is already in progress. |
422 | Request validation or provider-card capability/state failure. |
429 | A rate limit was exceeded. |
500 | Unexpected application failure. |
502 | Provider-card checkout could not obtain a usable provider response. |
Endpoint-Specific Cases
Section titled “Endpoint-Specific Cases”The labels in this table are suggested client-side categories. They are not wire fields returned by CoinsSend.
| Client category | HTTP status | Endpoint / condition | Wire shape |
|---|---|---|---|
missing_headers | 400 | Authenticated endpoint without Merchant or Sign | {"error":"Missing headers"} |
missing_timestamp | 400 | Withdrawal without Timestamp/X-Timestamp | {"error":"Missing timestamp"} |
invalid_signature | 401 | Signature mismatch | {"error":"Invalid sign"} |
timestamp_expired | 401 | Invalid or stale timestamp | {"error":"Timestamp expired"} |
invoice_order_conflict | 409 | Duplicate merchant order_id | endpoint error |
validation_failed | 422 | Invalid invoice, wallet, or withdrawal input | validation error |
withdrawal_permission_denied | 400 | API key lacks withdrawal permission | endpoint error |
withdrawal_rejected | 400 | Balance/fee/service rejection | endpoint error with possible extra fields |
provider_card_unavailable | usually 422 | Current availability or invoice state blocks checkout | endpoint error with failure_code |
wallet_creation_in_progress | 409 | Merchant-scoped wallet lock conflict | endpoint error |
Robust Parsing
Section titled “Robust Parsing”<?php
function apiErrorMessage(array $body, int $httpStatus): string{ return (string) ($body['error'] ?? $body['message'] ?? "HTTP {$httpStatus}");}
function validationErrors(array $body): array{ return is_array($body['errors'] ?? null) ? $body['errors'] : [];}async function parseCoinsSendResponse(response) { const body = await response.json()
if (!response.ok) { const error = new Error(body.error || body.message || `HTTP ${response.status}`) error.httpStatus = response.status error.validationErrors = body.errors || {} error.failureCode = body.failure_code throw error }
return body.data}def parse_coinssend_response(response): body = response.json() if response.ok: return body.get('data')
message = body.get('error') or body.get('message') or f'HTTP {response.status_code}' error = RuntimeError(message) error.http_status = response.status_code error.validation_errors = body.get('errors', {}) error.failure_code = body.get('failure_code') raise errorRetry Safety
Section titled “Retry Safety”Automatically retry only verified read operations with bounded exponential backoff and jitter. A timeout on a write does not prove the server rejected it.
- Duplicate invoice
order_idreturns409; it does not replay the first response. - Withdrawals have no request idempotency key.
- Static-wallet creation can create another address when repeated.
- Provider-card creation only reuses an already-active order; this is not a general idempotency contract.
Reconcile an unknown write outcome instead of blindly resubmitting it. Full guidance is in Rate Limits and Safe Retries.
Troubleshooting Invalid Signatures
Section titled “Troubleshooting Invalid Signatures”- Generate the PHP-compatible canonical JSON described in Authentication.
- Sign and send the same immutable canonical string.
- Use strings for monetary amounts.
- For withdrawals, recompute a fresh timestamp and HMAC.
- Run the client against
signature-test-vectors.json, including the URL/Unicode vector. - Remember that webhook verification is different: it uses the exact raw received body bytes.
The exact machine-readable response schemas are in OpenAPI.