Best practices
| What | Why |
|---|---|
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 state | After 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., not on the message text | The message text is not part of the contract and may change |
Store both invoice_id and merchant_order_id | The first is the platform’s key, the second is yours; an invoice can be looked up by either |
| Keep the callback handler fast | Answer 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 customer | While the previous one is open, a new order gets 409 with the existing id in error.: read it or cancel it. Both the sandbox and production behave this way |
| Exercise both outcomes of recurring charges | The 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 sandbox | The demo login is shared by everyone who opened this page: your test operations are visible to others, and theirs to you |