Common pitfalls

Assumptions that look safe on the v1 contracts and are not.

Every v1 contract

Assumption Actual behaviour
HTTP 200 means it worked On payouts, validation failures are returned as HTTP 200 with the error in the XML body.
A timeout means it failed It means you do not know. Retry the identical request.
An unknown status is a failure Leave it unresolved and keep polling.
Your polling timeout resolves the transaction It resolves nothing. The transaction is still live and can still complete.
Sorting JSON keys before signing is harmless It changes the signature wherever a body is signed.
A callback is proof It is a notification. Re-read the transaction.
A payer landing on your return URL means paid It means the browser came back. Read the status.

Pay-ins — Apple Pay and Google Pay

Assumption Actual behaviour
Signing a pretty-printed body Rejected. Sign the compact JSON you actually transmit.
Dropping null fields before signing Rejected. Everything you send is signed.
Uppercase hex digest Rejected. Lowercase hex.
Branching on order_scheduled or redirect_pending Both are deprecated and handled as pending. Act on redirect_data: send the buyer to redirect_data.url whenever it is present; some payments start only there and fail after 10 minutes.
Waiting for a webhook as the only signal Poll GET /sdk-partner/alternative-mobile-pay/mobile-pay/{id}/status from 5 seconds after the create until the status is final.
Treating refunded as a full refund It appears for partial refunds too. Read refunded_amount.
Missing X-Signature on an error response Authentication failures are rejected before the signing key is resolved. Absence is expected there.

Pay-ins — card payments

Assumption Actual behaviour
status: 1 means paid It means authorization: funds are locked, not taken. The payment completes at 3.
Statuses are strings, as elsewhere in pay-ins They are integers here.
Signing the JSON before base64 sign is computed over the base64 string, not the JSON behind it.
Reusing the Apple Pay or Google Pay credentials Card payments have their own api_key and secret_key; the others do not authenticate.
api_key sent beside data It belongs inside the encoded data document.
8 is a failure The provider had a temporary problem and returned a payment form link. Redirect the payer.
A refund that has not settled is lost 15 means refund processing, which can take 1–7 days.

Payouts

Assumption Actual behaviour
Reading OK as success OK means accepted for processing. The result comes later, by callback or check.
Reading PROCESSING as a problem It is also normal, and a core timeout is reported the same way.
Retrying with a changed amount under the same id The original payout is returned silently. Your new amount is ignored and no error is raised.
Joining signature fields with a delimiter The hash is MD5 of the fields concatenated with nothing between them, then secret_key.
Leaving an optional field empty and including it in the hash Empty fields are skipped. Include only what the endpoint's formula lists.
Parsing the <error> text It is free-form prose with no stable codes. Treat it as a log line, not a branch condition.