Appearance
Callbacks & Return Flow
Callback Mechanism
When a payment session reaches a terminal state, Spayon sends a signed POST request to your configured callback_url.
Callback Request
http
POST YOUR_CALLBACK_URL
Content-Type: application/json
X-Signature: <HMAC_SHA256_SIGNATURE>Callback Payload
json
{
"status": "failed",
"price": "5000.00",
"orderId": "ORDER_123456",
"currency": "AMD",
"sessionId": "3963253a-6230-4a80-9dd0-b7924b1c555f",
"createdAt": "2026-06-10T17:39:21.010Z",
"updatedAt": "2026-06-10T17:40:00.924Z",
"productName": "iPhone 16 Pro case",
"declineReasons": [
{
"transactionId": 161,
"responseCode": "1A",
"responseReasonEn": "3D-Secure authentication failed"
}
]
}All timestamps are in UTC, ISO 8601 format.
Status Values
| Status | Description |
|---|---|
paid | Payment completed successfully |
failed | Payment failed or was cancelled |
pending | Payment is still being processed |
expired | Session has expired |
Decline Reasons
When a session fails, the payload includes a declineReasons array with one entry per declined payment attempt within the session.
| Field | Type | Description |
|---|---|---|
transactionId | number | Identifier of the declined payment attempt |
responseCode | string | Decline code — see Decline Response Codes |
responseReasonEn | string | Human-readable decline reason in English |
Decline Response Codes
Each responseCode maps to a single decline reason. Standard codes follow ISO 8583; SP-XX codes are internal Spayon codes. The Source column indicates where the decline originated: CLIENT (payer side), BANK (card-issuing bank) or ACQUIRER (acquirer/gateway side).
| Code | Standard | Reason | Source | Description |
|---|---|---|---|---|
05 | ISO 8583 | Card bank declined the transaction | BANK | The card bank declined the transaction without a specific reason (Do Not Honor, often the bank's internal anti-fraud) |
14 | ISO 8583 | Invalid card data | CLIENT | A non-existent or incorrect card number, CVV or expiry date was entered |
1A | EMV 3DS | 3D-Secure authentication failed | CLIENT | 3D-Secure authentication failed: the customer cancelled, ran out of time, or entered a wrong OTP |
30 | ISO 8583 | Invalid request data | CLIENT | Invalid data format in the request (incorrect email/phone/field) |
51 | ISO 8583 | Insufficient funds | CLIENT | The card does not have enough funds to complete the transaction |
57 | ISO 8583 | Card does not support 3DS | CLIENT | The card does not support 3D-Secure; Spayon does not serve non-3DS cards |
59 | ISO 8583 | Suspected fraud | BANK | The bank's or gateway's anti-fraud suspected fraud and blocked the transaction |
61 | ISO 8583 | Card limit exceeded | CLIENT | The card limit by amount or number of transactions has been exceeded |
62 | ISO 8583 | Card restricted, lost or inactive | BANK | The card is blocked, lost, stolen or inactive |
91 | ISO 8583 | Card bank unavailable | BANK | The card-issuing bank is temporarily unavailable — no response to the authorization request |
92 | ISO 8583 | Card geo not supported | CLIENT | The card is from a region this terminal does not serve |
96 | ISO 8583 | Acquirer system malfunction | ACQUIRER | A technical failure on the acquirer's or gateway's side |
SP-03 | Spayon | Session expired | CLIENT | The payment time expired — the customer did not complete the flow |
SP-13 | Spayon | Acquirer limit reached | ACQUIRER | The processing limit on the acquirer/processing side has been reached |
SP-15 | Spayon | Order not found or processing unavailable | ACQUIRER | The order was not found in the system, or processing is temporarily unavailable |
SP-16 | Spayon | No payment attempted (wrong terminal) | CLIENT | The customer landed on a checkout for a terminal that does not fit their card or region and closed the form without attempting payment |
SP-99 | Spayon | Unclassified gateway code | ACQUIRER | A gateway code that could not be decoded |
Signature Verification
Every callback includes an X-Signature header. Always verify this signature before processing the payload to ensure the request originated from Spayon.
X-Signature = HMAC_SHA256(callback_secret, raw_request_body)callback_secret— obtained from your Vendor Admin Panelraw_request_body— the exact raw JSON bytes received (before any parsing)
WARNING
Compute the HMAC over the raw body bytes, not a re-serialized version. JSON key ordering or whitespace differences will cause verification to fail.
Verification Example
js
const crypto = require('crypto')
function verifySignature(rawBody, receivedSignature, secret) {
const expected = crypto
.createHmac('sha256', secret)
.update(rawBody)
.digest('hex')
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(receivedSignature)
)
}python
import hmac
import hashlib
def verify_signature(raw_body: bytes, received_signature: str, secret: str) -> bool:
expected = hmac.new(
secret.encode(),
raw_body,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, received_signature)Retry Logic
| Property | Value |
|---|---|
| Retries | Up to 3 attempts |
| Retry interval | 5 minutes between attempts |
| On timeout | No callback sent for sessions that never reached a terminal state |
TIP
Your callback endpoint must return a 2xx response quickly. If your endpoint is slow or returns an error, Spayon will retry.
Return URL Flow
After payment completes (success or failure), the user is redirected to your return_url. If the user clicks the back button on the payment page, they are redirected to your cancel_url (if configured).
The sessionId is always appended as a query parameter:
https://example.com/thank-you?sessionId=4ae3108a-3a1c-42df-bce9-503bbd70ab24Cancel URL behavior
Redirecting to the cancel_url does not change the session status. The session remains active until it expires (15 minutes) or payment is processed. Do not treat a cancel redirect as a definitive cancellation.
| URL | Triggered when |
|---|---|
return_url | Payment completes (any status) |
cancel_url | User clicks the back button on the payment page |