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
{
  "sessionId": "4ae3108a-3a1c-42df-bce9-503bbd70ab24",
  "status": "paid",
  "productName": "Iphone 16S",
  "price": "10",
  "currency": "AMD",
  "createdAt": "2025-06-11T17:02:51.118Z",
  "updatedAt": "2025-06-11T17:03:15.202Z",
  "orderId": "ORDER_123456"
}

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

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 session_id is always appended as a query parameter:

https://example.com/thank-you?session_id=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