Common pitfalls
Assumptions that look safe and are not. The rule column points to Integration rules.
| Assumption | Actual behaviour | Rule |
|---|---|---|
| One key for payins and payouts | A key belongs to one shop of one type | R1 |
| A production key works in the sandbox | Sandbox and production keys work only on their own host | R2 |
| Passing the method in the body | The endpoint selects the method | R3 |
| A method in the contract is enabled for you | It may not be: 403 method_not_enabled |
R3 |
| A retry needs a new reference "to be safe" | It creates a second transaction. Resend the same reference and body | R4, R6 |
| Changing the amount and resending with the same reference | 409 merchant_reference_conflict |
R4 |
HTTP 201 means paid |
It means recorded. Read data.status |
R8 |
| A decline comes back as an error | The request succeeds; the transaction ends failed |
R9 |
A voided hold is canceled |
It is failed with canceled_by_merchant |
R9 |
The payer returning to return_urls.success means paid |
It means the browser came back | R8, R18 |
Treating authorized as paid |
It is a hold. Call capture or void |
R11 |
| A failed capture or void is final | The payin returns to authorized |
R11 |
Treating a refunded payin as unpaid |
It was charged; refunded_amount says how much came back. The refund is its own transaction |
R12 |
| The enum lists in the contract are complete | Values are added without a new version | R13 |
| A webhook on every status | Only on requires_action (Google Pay, BLIK), authorized, capture_failed, void_failed and final statuses |
— |
| One secret for every shop's webhooks | Each shop signs with its own secret; route by URL or shop_id |
R15 |
| Marking an event as seen before processing it | A failure after that loses the event for good | R17 |
| Polling the status instead of waiting for webhooks | Loads the API and gets 429 rate_limited; poll only after a minute without a webhook |
R20 |
Syncing with created_from or newest-first pages |
Misses later status changes; use order=updated_asc and updated_from |
R19 |
| Signing the webhook body alone, or a re-serialized body | The signature covers <t>.<raw body> as received |
R15 |
| BLIK refunds work | Not supported yet: 501 not_supported_yet |
— |
| Sending raw card numbers is fine from any backend | It puts you in PCI DSS scope. Wallets, BLIK and the payment form do not | — |