Mozarto - The Payments Orchestration Platform
    • 1. Introduction
    • 2. Quick Start
    • 3. Authentication
    • 4. Webhook Setup
    • 5. Errors
    • 6. Redirect flow
      • Pay-In Flow
      • Pay-Out Flow
    • 7. Payment Providers (PSPs)
      • Overview
      • Brite
      • Cleo
      • Flexepin
      • ForumPay
      • Gigadat
      • Neosurf
      • PayOne
      • Trust Payments
      • Worldpay
      • Emerchantpay
    • 8. Redirect Flow APIs
      • Redirect Flow APIs - overview
      • Pay-In
        • WorldPay
        • Forumpay
        • Payone
        • Gigadat
        • Flexepin
        • Trust
      • Pay-Out
        • Forumpay
        • Payone
        • Gigadat withdraw ETO
        • Gigadat withdraw ACH
      • Webhook
        • Payone status webhook
    • Schemas
      • TransactionData

    4. Webhook Setup

    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.

    Configuration#

    Set your webhook URL in the Mozarto back office when configuring a payment provider account:
    Go to Admin - Configuration - Payment Methods
    Select your PSP account
    Set webhookUrl (and optionally enable webhook security)
    webhookUrl: your HTTPS endpoint that receives POST requests from Mozarto
    isWebhookSecured: when enabled, Mozarto includes an Authorization header in webhook calls so you can verify the request (shared secret)
    Your webhookUrl must:
    Be publicly reachable over HTTPS
    Accept POST requests with Content-Type: application/json
    Respond with HTTP 200 within 10 seconds
    If your endpoint does not respond with 200 OK within 10 seconds (timeout or non-2xx), the delivery is treated as failed and may be retried. Your handler must be idempotent and safe to process duplicates.

    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
    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 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#

    Enable webhook security from the Mozarto back office on the PSP account configuration (toggle Webhook security / isWebhookSecured). When enabled, Mozarto adds an Authorization header to each webhook call:
    POST https://your-platform.com/webhooks/mozarto
    Authorization: <your-configured-password>
    Content-Type: application/json
    Validate this header in your webhook handler before processing the payload:
    This uses a shared secret, not a cryptographic signature. For additional protection, also validate that transaction_id matches a known pending transaction in your database before applying any balance changes.

    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 transaction_id as the idempotency key.
    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 isWebhookSecured is enabled, prefer testing against your own endpoint so you can validate the Authorization header.
    Modified at 2026-06-11 13:52:28
    Previous
    3. Authentication
    Next
    5. Errors
    Built with