verify() and settle() throw on failure rather than returning a falsy result — there is no { isValid: false } shape to check. Wrap calls in try/catch and use the error classes below to decide how to respond.
Error classes
HTTP status mapping
The facilitator’s error handler returns consistent error responses with these status codes:A
402 response from /verify or /settle is a normal, expected outcome for an invalid or expired payment — not a bug in your integration. Surface err.message back to the payer in your own 402 challenge response’s error field (see Resource Server Guide) so their agent can retry correctly.Automatic retries
Requests are retried automatically onX402FacilitatorNetworkError (i.e. the request never got a response at all) with exponential backoff and jitter:
Requests that do get a response — including
402s and other HTTP error statuses — are not retried automatically, since a 402 or 4xx is a deterministic outcome that won’t change on retry without a different payload.
Common scenarios
X402FacilitatorConfigError: apiKey is required
X402FacilitatorConfigError: apiKey is required
Thrown immediately by the constructor if
apiKey (or orgId) is missing. Check your environment variables (WAAS_API_KEY, WAAS_ORG_ID) are set before constructing X402FacilitatorClient.402 from verify() — invalid signature
402 from verify() — invalid signature
The signed EIP-712 message doesn’t match what the contract/facilitator expects — usually a wrong
Eip3009TokenDomain (see Signing Reference) or a payload that was tampered with in transit.402 from settle() — nonce already used
402 from settle() — nonce already used
The same
(from, nonce) pair was already submitted on-chain. If you intentionally reuse deterministic nonces for idempotency, this is expected on a genuine retry of an already-settled payment — check xentfi_get_payment-style transaction history (or your own settlement log) before treating it as an error.
