Aller au contenu
CoinsSendDéveloppeurs
Documentation Payments

Error Handling

Voir le MarkdownConfigurer un agent

Ce contenu n’est pas encore disponible dans votre langue.

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.

Most successful operations return:

{
"data": {},
"status": "success"
}

Successful write operations currently return HTTP 200, including asynchronous withdrawal submission.

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 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 failures use HTTP 422:

{
"errors": {
"amount": [
"The amount field is required."
]
},
"status": "error",
"message": "The given data was invalid."
}

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.

StatusMeaning in the public contract
400Missing auth input or an endpoint rejection. Withdrawal permission denial currently uses this status.
401Invalid merchant/signature or expired timestamp.
403Suspended/blocked merchant state or authorization failure.
404Public invoice or QR resource not found.
409Invoice order_id already exists, or wallet creation is already in progress.
422Request validation or provider-card capability/state failure.
429A rate limit was exceeded.
500Unexpected application failure.
502Provider-card checkout could not obtain a usable provider response.

The labels in this table are suggested client-side categories. They are not wire fields returned by CoinsSend.

Client categoryHTTP statusEndpoint / conditionWire shape
missing_headers400Authenticated endpoint without Merchant or Sign{"error":"Missing headers"}
missing_timestamp400Withdrawal without Timestamp/X-Timestamp{"error":"Missing timestamp"}
invalid_signature401Signature mismatch{"error":"Invalid sign"}
timestamp_expired401Invalid or stale timestamp{"error":"Timestamp expired"}
invoice_order_conflict409Duplicate merchant order_idendpoint error
validation_failed422Invalid invoice, wallet, or withdrawal inputvalidation error
withdrawal_permission_denied400API key lacks withdrawal permissionendpoint error
withdrawal_rejected400Balance/fee/service rejectionendpoint error with possible extra fields
provider_card_unavailableusually 422Current availability or invoice state blocks checkoutendpoint error with failure_code
wallet_creation_in_progress409Merchant-scoped wallet lock conflictendpoint error
<?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 error

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_id returns 409; 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.

  • 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.