1. 3. Redirect API
Mozarto - The Payments Orchestration Platform
  • 1. Introduction
  • 2. Authentication
  • 3. Redirect API
    • Pay-In Flow
    • Pay-Out Flow
    • Webhook Setup
    • Country Codes
    • Errors
    • Payment Providers (PSPs)
      • Overview
      • Brite
      • CashLib
      • Cleo
      • Contiant
      • emerchantpay
      • Flexepin
      • ForumPay
      • Gigadat
      • Neosurf
      • OFApay
      • PawaPay
      • PayModum
      • PayOne
      • Trust Payments
      • Worldpay
    • Sample requests
      • Overview
      • Pay-In
        • Brite
        • CashLib
        • Cleo
        • Contiant
        • emerchantpay
        • Flexepin
        • Forumpay
        • Gigadat
        • Neosurf
        • OFApay
        • PawaPay
        • Paymodum
        • PayOne
        • Trust Payments
        • WorldPay
      • Pay-Out
        • Cleo
        • Forumpay
        • Gigadat withdraw ACH
        • Gigadat withdraw ETO
        • OFApay
        • PawaPay
        • PayOne
        • Trust Payments
      • Webhook
        • PayOne status webhook
        • ForumPay status webhook
  • 4. Hosted page API
    • Pay-In Flow
    • Webhook Setup
    • Country Codes
    • Errors
    • Payment Providers (PSPs)
      • emerchantpay
      • Worldpay
      • Overview
    • Sample requests
      • Overview
  • Schemas
    • TransactionData
  1. 3. Redirect API

Webhook Setup

Webhooks are how Mozarto delivers transaction status updates to your platform. For most providers the payment flow is asynchronous - the Pay-In/Pay-Out call creates the transaction (returning status: "PENDING" in the API response), but the confirmed or failed outcome arrives later via webhook.
The Hosted page API sends the same webhook, with the same signature and retries. See Hosted page API - Webhook Setup for when it is sent.

Configuration#

Set your webhook URL in the Mozarto back office when configuring a payment provider account:
Go to Payments Module and select your brand
Open your PSP account
Unlock the API Credentials section of the Processing Scope tab with your 2FA code (see Unlock API credentials)
Set webhookUrl in that section. Add more URLs if several systems need the same notification
Each webhook includes an Authorization header you verify to confirm the request came from Mozarto. See Securing webhooks.

Which URL receives the webhook#

RequestTarget
webhookUrl sent in the request bodyOnly that URL
No webhookUrl in the requestEvery webhook URL configured on the provider account that processed the transaction

Endpoint requirements#

Your webhook endpoint must:
Be publicly reachable over HTTPS
Accept POST requests with Content-Type: application/json
Respond with a 2xx status within 5 seconds

Headers#

HeaderDescription
AuthorizationSignature - verify it before acting. See Securing webhooks
X-Webhook-IdUnique ID of this delivery. A retry of the same delivery carries the same ID
X-Webhook-AttemptAttempt number, starting at 1

Retries#

Your responseWhat Mozarto does
2xxDelivered. No retry
Timeout, network error, 408, 429, or 5xxRetries up to 6 more times: after about 1 minute, 5 minutes, 15 minutes, 1 hour, 3 hours, and 6 hours (about 10.5 hours in total)
Any other 4xxTreated as a final rejection. No retry
A Retry-After header on a 429 or 5xx response is honoured, up to 1 hour. Each URL is retried independently. Your handler must be idempotent and safe to process duplicates - see Handling duplicate deliveries.

Webhook payload#

Mozarto sends a JSON body to your webhookUrl:
{
  "transaction_id": "64a1f2b3c4d5e6f7a8b9c0d1",
  "psp_transaction_id": "HS923856HU",
  "user_id": "user_123",
  "status": "confirmed",
  "transaction_status": "Approved",
  "message": "Crypto payment confirmed and successfully processed",
  "amount": "100.00",
  "currency": "EUR",
  "merchantReference": "your-internal-ref"
}

Payload fields#

FieldTypeRequiredDescription
transaction_idstringYesMozarto transaction ID - use this to look up the transaction on your side
psp_transaction_idstringNoPSP internal transaction ID - format and presence varies by provider
user_idstringYesThe player/user ID passed in the original request
statusstringYesRaw provider or internal status string - PSP-specific, not normalized (see note below)
transaction_statusstringYesNormalized Mozarto status - use this for business logic (see table below)
messagestringYesHuman-readable description of the outcome
amountstringYesTransaction amount
currencystringNoCurrency code (when available from provider)
merchantReferencestringNoThe merchant reference you passed in the original request - empty string if not set
Use transaction_status for business logic, not status. The status field contains the raw state string from the payment provider (e.g. "confirmed" for ForumPay, "success" for others). The transaction_status field is always a normalized Mozarto value regardless of provider.

Transaction states#

Pay-In lifecycle#

Pay-Out lifecycle#

transaction_status values (normalized - use these for business decisions)#

transaction_statusMeaningAction
ApprovedPayment completed successfullyCredit the user / fulfil the order
DeclinedPayment declined by providerNotify the user, allow retry
FailedPayment failedNotify the user, allow retry
CancelledPayment cancelled by user or expiredNotify the user, allow retry
RejectedPay-Out rejected during a manual approval step (payout only)Do not debit the user; notify and stop processing
InitiatedTransaction created, in authentication stageWait for next webhook
On HoldTransaction held for manual reviewAwait operator action
PendingPayment in progress, not yet finalWait for next webhook
ProcessingPayout is being processed (payout only)Wait for next webhook
Only Approved, Declined, Failed, Cancelled, and Rejected are terminal states. Do not update the user's account for Initiated, Pending, Processing, or On Hold.

Relationship to the initial API response#

When you call POST /v1/api/mozarto/cashier, the response always contains data.status: "PENDING" - this is the transaction creation status. The webhook delivers subsequent updates as the transaction progresses through the PSP. The transaction_status values above are what the transaction can transition to after that initial PENDING state.

Securing webhooks#

Each webhook carries an Authorization header that proves the request came from Mozarto. The header is not a static password. It is the fixed string signature encrypted with your API key using AES:
Authorization = AES_encrypt("signature", <your API key>)
The secret is your API key - the same live_ key issued during onboarding. Find it in the Mozarto back office under Admin Center - API Credentials (the Api Key field), after unlocking the page with your 2FA code. Mozarto never sends the key itself, only data encrypted with it, so a valid Authorization header proves authenticity.
A fresh random salt is used on every call, so the token value changes each time. Do not compare it against a fixed expected string. Decrypt it and confirm the plaintext equals signature.
The token uses the CryptoJS AES passphrase format (OpenSSL Salted__): a Base64 payload whose decoded bytes begin with Salted__, followed by an 8-byte salt and the ciphertext. The key and IV are derived from your API key and the salt using OpenSSL EVP_BytesToKey (MD5).

Verify the signature#

1.
Read the Authorization header from the incoming request.
2.
AES-decrypt it using your API key as the passphrase.
3.
Confirm the decrypted plaintext equals signature. If it matches, the webhook is authentic. Otherwise, reject the request.
Node.js (CryptoJS):
For other languages, use a CryptoJS-compatible AES library (for example brainfoolong/cryptojs-aes-php for PHP), or decrypt the OpenSSL Salted__ payload directly using the format described above.
Verification only proves authenticity. For high-value flows, also reconcile the final status against your records using transaction_id / merchantReference before applying any balance change.

Handling duplicate deliveries#

Mozarto does not guarantee exactly-once delivery. If the provider sends a duplicate callback, Mozarto may call your webhookUrl more than once for the same transaction.
Protect against this with an idempotency check on your side:
Use X-Webhook-Id to drop a retry of a delivery you already processed.
Use transaction_id as the idempotency key for side effects.
Store the last processed terminal transaction_status for each transaction_id in your database.
If you receive the same transaction_id again with the same or earlier status, return 200 OK without re-applying side effects (credit/debit).

Resending a webhook#

If your endpoint was temporarily unavailable, ask a Mozarto operator to resend the webhook from the back office:
Open Transactions, find the transaction by transaction_id, open the row actions and select Resend webhook.

Testing webhooks locally#

Mozarto must be able to reach your webhookUrl over HTTPS. During development your server runs on localhost, which is not publicly reachable. Use ngrok to create a temporary public HTTPS URL that tunnels to your local server:
Every request Mozarto sends to that URL is forwarded to your local process in real time. The ngrok terminal also shows each request and response so you can inspect headers and payloads without adding any logging to your code.

Testing with Webhook.site#

Staging and sandbox only. Webhook.site is permitted for staging and sandbox testing only. It is not whitelisted in production, and webhook delivery to webhook.site URLs is blocked there. Use a webhook URL on your own domain for production.
For a quick smoke test (no local server required), you can use Webhook.site to generate a temporary public URL and inspect incoming webhook requests.
1.
Create a new URL in Webhook.site (it will look like https://webhook.site/<uuid>).
2.
Set that URL as your webhookUrl in the Mozarto back office.
3.
Trigger a test transaction (or resend a webhook) and verify the request appears in Webhook.site.
You can also send a sample request yourself to confirm your tooling:
Do not use third-party endpoints for production secrets. If webhook security is enabled, prefer testing against your own endpoint so you can validate the Authorization header.
Modified at 2026-11-02 13:14:37
Previous
Pay-Out Flow
Next
Country Codes
Built with