Skip to content

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

StatusDescription
paidPayment completed successfully
failedPayment failed or was cancelled
pendingPayment is still being processed
expiredSession has expired

Decline Reasons

When a session fails, the payload includes a declineReasons array with one entry per declined payment attempt within the session.

FieldTypeDescription
transactionIdnumberIdentifier of the declined payment attempt
responseCodestringDecline code — see Decline Response Codes
responseReasonEnstringHuman-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).

CodeStandardReasonSourceDescription
05ISO 8583Card bank declined the transactionBANKThe card bank declined the transaction without a specific reason (Do Not Honor, often the bank's internal anti-fraud)
14ISO 8583Invalid card dataCLIENTA non-existent or incorrect card number, CVV or expiry date was entered
1AEMV 3DS3D-Secure authentication failedCLIENT3D-Secure authentication failed: the customer cancelled, ran out of time, or entered a wrong OTP
30ISO 8583Invalid request dataCLIENTInvalid data format in the request (incorrect email/phone/field)
51ISO 8583Insufficient fundsCLIENTThe card does not have enough funds to complete the transaction
57ISO 8583Card does not support 3DSCLIENTThe card does not support 3D-Secure; Spayon does not serve non-3DS cards
59ISO 8583Suspected fraudBANKThe bank's or gateway's anti-fraud suspected fraud and blocked the transaction
61ISO 8583Card limit exceededCLIENTThe card limit by amount or number of transactions has been exceeded
62ISO 8583Card restricted, lost or inactiveBANKThe card is blocked, lost, stolen or inactive
91ISO 8583Card bank unavailableBANKThe card-issuing bank is temporarily unavailable — no response to the authorization request
92ISO 8583Card geo not supportedCLIENTThe card is from a region this terminal does not serve
96ISO 8583Acquirer system malfunctionACQUIRERA technical failure on the acquirer's or gateway's side
SP-03SpayonSession expiredCLIENTThe payment time expired — the customer did not complete the flow
SP-13SpayonAcquirer limit reachedACQUIRERThe processing limit on the acquirer/processing side has been reached
SP-15SpayonOrder not found or processing unavailableACQUIRERThe order was not found in the system, or processing is temporarily unavailable
SP-16SpayonNo payment attempted (wrong terminal)CLIENTThe customer landed on a checkout for a terminal that does not fit their card or region and closed the form without attempting payment
SP-99SpayonUnclassified gateway codeACQUIRERA 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 Panel
  • raw_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

PropertyValue
RetriesUp to 3 attempts
Retry interval5 minutes between attempts
On timeoutNo 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-503bbd70ab24

Cancel 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.

URLTriggered when
return_urlPayment completes (any status)
cancel_urlUser clicks the back button on the payment page