Zum Inhalt springen
CoinsSendEntwickler
Payments-Dokumentation

Error Handling

Markdown öffnenAgent einrichten

Dieser Inhalt ist noch nicht in deiner Sprache verfügbar.

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.