Skip to Content

Best practices

WhatWhy
Treat callbacks as repeatable and deduplicate by the event identifier (id, event_id in the legacy envelope)The same event may arrive several times; the identifier does not change between attempts, the attempt number is separate
Do not rely on callbacks as the only source of stateAfter the seventh failed attempt delivery stops — the next step would fall outside the sandbox’s one-minute window. The state is always available by polling GET /invoices/{invoice_id}
Branch on error.code, not on the message textThe message text is not part of the contract and may change
Store both invoice_id and merchant_order_idThe first is the platform’s key, the second is yours; an invoice can be looked up by either
Keep the callback handler fastAnswer 2xx immediately and move heavy work to a queue: the sender waits a limited time and treats a timeout as failure
Close an invoice before creating the next one for the same customerWhile the previous one is open, a new order gets 409 with the existing id in error.details.invoice_id: read it or cancel it. Both the sandbox and production behave this way
Exercise both outcomes of recurring chargesThe sandbox values SuccessSequencePayment and FailedSequencePayment let you exercise a contract failure without waiting for one in production
Do not use the demo credentials outside the sandboxThe demo login is shared by everyone who opened this page: your test operations are visible to others, and theirs to you