1. Payment Providers (PSPs)
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. Payment Providers (PSPs)

PayModum

US bank transfer (ACH) via PayModum. The payer verifies their identity, links their bank, and is risk-screened on PayModum-hosted pages, so no identity documents or bank credentials pass through the Mozarto API. Money is then moved by PayModum's Sponsor Bank: deposits are debited from the payer's bank, and payouts are sent back to the same bank the customer deposited from.
Operations: Pay-In ✓ | Pay-Out ✓ | Webhook ✓
Processing: Asynchronous - Pay-In redirects the payer to a hosted page; progress and the final outcome arrive by webhook
Payment type: Bank transfer (US ACH)
Currency / country: USD / US
Fields marked with * are required.

How the flow works#

Pay-In (deposit)#

#StepWhat happensMerchant webhook
1Identity VerificationThe payer verifies their identity on a PayModum hosted page. Skipped when the payer's latest verification already passed and their first name, last name, email and phone still matchidentity_verification.required → identity_verification.passed / .failed / .canceled
2AML / watchlist screeningPayModum Monitor screening, on every transactionwatchlist.failed if not cleared
3Bank linkingThe payer links their bank on a PayModum hosted pagebank_link.required → bank_link.completed / bank_link.failed
4ACH risk decisionPayModum Signal scores the debit. ACCEPT continues; REROUTE / REVIEW declinerisk_check.declined on decline
5Sponsor Bank debitThe payer's bank is debited through the Sponsor Bankpayment.processing → payment.settled, or payment.failed

Pay-Out (withdrawal) - closed loop#

Payouts are closed loop: the money is sent back to the bank account the customer last deposited from, and only once a deposit from that bank account is approved. If the customer links a new bank account, payouts wait until a deposit from the new account is approved, even if earlier deposits from another account were approved. There is no identity verification, screening, or bank linking step, and no redirect: the cashier call submits the payout directly.
#StepWhat happensMerchant webhook
1EligibilityThe customer (userId) must have an approved PayModum deposit and a verified bank on file(refusal is returned in the cashier response)
2Funds checkThe merchant's Sponsor Bank wallet must cover the amount(refusal is returned in the cashier response)
3PayoutSent from the wallet to the customer's bank - real-time (RTP) where the bank supports it, otherwise standard bank transfer / ACHpayment.processing → payment.settled, or payment.failed

Configuration (Mozarto back office)#

These fields are in the locked API Credentials section of the account's Processing Scope tab. Unlock it with your 2FA code first - see Unlock API credentials.
FieldDescription
Client ID *PayModum client_id (stored encrypted)
Secret Key *PayModum secret for the environment (stored encrypted)
Identity Verification Template ID *PayModum Identity Verification template id (idvtmp_...)
Watchlist / Monitor Program ID *PayModum Monitor program id (prg_...) used for AML / watchlist screening
Sponsor Bank Wallet ID *The merchant's marketplace wallet at the Sponsor Bank. Deposits are credited to it and payouts are funded from it
Webhook URL *Your HTTPS endpoint for step and final webhooks
Site URLFallback return URL for the payer after the hosted flow
Signal ruleset: the ACH risk decision uses the PayModum Signal ruleset with the key default. Create it in the PayModum Dashboard for your environment; without a ruleset, Signal returns scores only and the transaction proceeds on scores alone.
Payouts need a funded wallet. Payouts are refused with Insufficient wallet balance when the Sponsor Bank Wallet does not cover the amount.

Pay-In#

POST /v1/api/mozarto/cashier
Authentication is required on every cashier call. See Authentication. The userId you authenticate the payer with identifies the customer - use the same userId for every transaction of the same customer, since payouts are only allowed to a customer who deposited under that userId.
The cashier call creates the transaction and returns a paymentUrl. Redirect the payer to it; the identity, bank-linking and risk steps run on PayModum-hosted pages. Track progress and the outcome through the webhooks.

Request body#

FieldTypeDescription
pspType *stringAlways "PAYMODUM"
type *stringAlways "PAYIN"
baseamount *numberAmount in the currency's main unit, up to 2 decimals (e.g. 200 = 200 USD)
currency *string"USD"
country *stringPayer's country - full name, ISO 3166-1 alpha-2, or alpha-3 (e.g. "United States", "US"). See Country codes
firstName *stringPayer first name - prefills Identity Verification and is matched against a prior verification
lastName *stringPayer last name
email *stringPayer email
phonestringPayer phone in E.164 (e.g. "+14155550123")
dobstringDate of birth, YYYY-MM-DD
ssnstringUS SSN (9 digits) - prefills the KYC data-source check
addressstringStreet address
citystringCity
statestringState / region
zipCodestringZIP / postal code
merchantReferencestringYour order reference, echoed back on every webhook
webhookUrlstringHTTPS endpoint for this transaction's webhooks. Overrides the configured Webhook URL
siteUrlstringReturn URL for the payer after the hosted flow. Overrides the configured Site URL
Identity re-use: a returning payer whose latest Identity Verification already passed skips verification - but only when firstName, lastName, email and phone all match the verified identity. Any mismatch, or a first-time payer, runs verification (identity_verification.required tells you which case applied). Values are compared ignoring case and spacing, and phone numbers by digits only.
For a mismatch, data.mismatched_fields lists each field that differed and why - different (both sent, not equal), not_in_request (you didn't send it) or not_on_verification (the earlier verification doesn't have it). Only field names are returned, never the values:
"data": {
  "reason": "re_verify_mismatch",
  "mismatched_fields": [{ "field": "phone", "issue": "not_in_request" }],
  "action": "redirect",
  "paymentUrl": "https://verify.plaid.com/verify/idv_..."
}

Example request#

{
  "pspType": "PAYMODUM",
  "type": "PAYIN",
  "baseamount": 200,
  "currency": "USD",
  "country": "US",
  "firstName": "Leslie",
  "lastName": "Knope",
  "email": "leslie.knope@example.com",
  "phone": "+14155550123",
  "dob": "1975-01-18",
  "ssn": "123456789",
  "address": "123 Main St",
  "city": "San Francisco",
  "state": "CA",
  "zipCode": "94111",
  "merchantReference": "ORDER-4821",
  "webhookUrl": "https://example.com/webhooks/mozarto"
}

Response#

{
  "status": "success",
  "message": "Successfully",
  "isSuccess": true,
  "data": {
    "transactionId": "6a95bf514824638671769f64",
    "merchantReference": "ORDER-4821",
    "amount": 200,
    "transaction_status": "Initiated",
    "paymentUrl": "https://verify.plaid.com/verify/idv_..."
  }
}
FieldTypeDescription
transactionIdstringMozarto transaction identifier - it arrives as transaction_id on every webhook
merchantReferencestringYour reference from the request, or an empty string
amountnumberThe transaction baseamount
transaction_statusstringAlways "Initiated" at this point
paymentUrlstringRedirect the payer here. It is the identity verification page, or - for a returning verified payer - the bank-linking page
If a step fails while the cashier call is being processed (for example screening of a returning payer), the call returns 400 with the reason and the matching failure webhook is sent.

Pay-Out#

POST /v1/api/mozarto/cashier
Set type to "PAYOUT". The payout is submitted immediately - there is no paymentUrl and no redirect.
Closed loop. Authenticate with the same userId the customer deposited with. A payout is refused unless that customer has an approved PayModum deposit; the funds go back to the bank account used for that deposit.

Request body#

FieldTypeDescription
pspType *stringAlways "PAYMODUM"
type *stringAlways "PAYOUT"
baseamount *numberAmount to send, in the currency's main unit (e.g. 200 = 200 USD)
currency *string"USD"
country *stringPayee's country - full name, ISO 3166-1 alpha-2, or alpha-3. See Country codes
firstNamestringPayee first name (defaults to the authenticated user's)
lastNamestringPayee last name (defaults to the authenticated user's)
emailstringPayee email (defaults to the authenticated user's)
phonestringPayee phone in E.164
merchantReferencestringYour reference, echoed back on every webhook
webhookUrlstringHTTPS endpoint for this transaction's webhooks. Overrides the configured Webhook URL
The payee's bank is not sent in the request - it is always the bank the customer last deposited from, once a deposit from it is approved.

Example request#

{
  "pspType": "PAYMODUM",
  "type": "PAYOUT",
  "baseamount": 200,
  "currency": "USD",
  "country": "US",
  "firstName": "Leslie",
  "lastName": "Knope",
  "email": "leslie.knope@example.com",
  "merchantReference": "PAYOUT-7723"
}

Response - submitted#

{
  "status": "success",
  "message": "Successfully",
  "isSuccess": true,
  "data": {
    "transactionId": "6a97e94a4608b3c3f6d46d6d",
    "merchantReference": "PAYOUT-7723",
    "amount": 200,
    "transaction_status": "Processing"
  }
}
The payout is on its way; payment.processing / payment.settled follow by webhook.

Response - refused#

A refused payout returns 400, and the transaction is stored with the status shown:
{
  "status": "error",
  "message": "Payout is only allowed to customers with an approved deposit",
  "isSuccess": false
}
messagetransaction_statusMeaning
Payout is only allowed to customers with an approved depositRejectedThis userId has never deposited with PayModum
Payout is only allowed once a deposit from the last linked bank account is approvedRejectedThe customer's last deposit bank has no approved deposit yet (still pending, or failed)
Last linked bank account is no longer verifiedRejectedThe customer's last deposit bank is no longer verified
Insufficient wallet balance (<balance> < <amount>)RejectedThe Sponsor Bank Wallet does not cover the payout
PSP configuration / provider errorFailedSponsor Bank Wallet ID missing, or a provider error
Refusals are returned only in the cashier response - no webhook is sent for them.

Webhook#

Mozarto calls your Webhook URL at each meaningful step and at the final outcome. Every webhook uses one envelope: read event and step to know what happened, data for step-specific detail, and transaction_status for the outcome.
{
  "event": "payment.settled",
  "step": "settlement",
  "psp": "PAYMODUM",
  "timestamp": "2026-09-27T09:03:27.209Z",
  "data": {
    "checkbook_status": "PAID",
    "checkbook_id": "0161e7058c6449ca897794b5f2a0c1d3"
  },
  "transaction_id": "6ab8d95bfb108233c80c2d2b",
  "psp_transaction_id": "0161e7058c6449ca897794b5f2a0c1d3",
  "user_id": "66f2612b330f684f99a633cb",
  "status": "success",
  "transaction_status": "Approved",
  "amount": 200,
  "currency": "USD",
  "merchantReference": "ORDER-4821"
}

Envelope fields#

FieldDescription
eventWhat happened - see the event catalog
stepThe flow stage: identity_verification, watchlist, bank_link, signal, sponsor_bank, settlement, or initiation
pspAlways "PAYMODUM"
timestampISO 8601 time the event was emitted
dataStep-specific detail (see catalog)
transaction_idMozarto transaction identifier (transactionId in the cashier response)
psp_transaction_idProvider reference. Pay-In: PayModum Item id once the bank is linked. Pay-Out: the Sponsor Bank payment id. Empty before that
user_idThe customer's userId
statusEvent outcome: success, failed, action_required, processing, or refunded
transaction_statusThe transaction's status after this event - see Transaction statuses. Use it for business logic
amountTransaction amount in the currency's main unit
currencyISO 4217 currency code
merchantReferenceYour reference from the original request, or an empty string

Event catalog#

eventstepstatustransaction_statusdataWhen
identity_verification.requiredidentity_verificationaction_requiredInitiatedreason, action, paymentUrl, and mismatched_fields when reason is re_verify_mismatchVerification is needed. reason: first_time, re_verify_mismatch (details differ from the verified identity) or retry (previous attempt did not pass)
identity_verification.passedidentity_verificationsuccessInitiatedidv_status, or reason: "previously_verified"Identity verified - or verification skipped for a returning verified payer
identity_verification.failedidentity_verificationfailedFailedreason, idv_statusVerification declined (failed / pending_review / expired)
identity_verification.canceledidentity_verificationfailedFailedreason, idv_statusVerification abandoned or superseded by a newer attempt
watchlist.failedwatchlistfailedFailedreason, watchlist_statusAML / watchlist screening not cleared
bank_link.requiredbank_linkaction_requiredInitiatedaction, paymentUrlRedirect the payer to the bank-linking page
bank_link.completedbank_linksuccessInitiateditem_id, account_idThe payer linked their bank
bank_link.failedbank_linkfailedFailedreason, error_code, error_messageBank linking ended with an unrecoverable error
risk_check.declinedsignalfailedFailedreason, ruleset_result, customer_return_risk, bank_return_riskSignal returned REROUTE / REVIEW
payment.processingsettlementprocessingPending (Pay-In) / Processing (Pay-Out)checkbook_status, checkbook_idThe Sponsor Bank accepted the debit / payout and it is in flight
payment.settledsettlementsuccessApprovedcheckbook_status, checkbook_idFunds settled - final success
payment.failedsponsor_bank or settlementfailedFailedreason (+ provider), or checkbook_status, checkbook_idThe Sponsor Bank submission failed (sponsor_bank), or the payment failed / was voided / expired (settlement)
payment.refundedsettlementrefundedRefundedcheckbook_status, checkbook_idA settled payment was returned to the payer
data.checkbook_status and data.checkbook_id are the Sponsor Bank's own status and payment id, for reconciliation.

Webhook sequence by scenario#

ScenarioWebhooks (in order)
Pay-In, first-time payer - settledidentity_verification.required → identity_verification.passed → bank_link.required → bank_link.completed → payment.processing → payment.settled
Pay-In, returning verified payer - settledidentity_verification.passed (previously_verified) → bank_link.required → bank_link.completed → payment.processing → payment.settled
Pay-In, identity details changedidentity_verification.required (re_verify_mismatch) → then as a first-time payer
Identity declinedidentity_verification.required → identity_verification.failed
Verification abandoned / supersededidentity_verification.required → identity_verification.canceled
Watchlist not cleared… → watchlist.failed
Bank linking failed… → bank_link.required → bank_link.failed
Risk declined… → bank_link.completed → risk_check.declined
Sponsor Bank submission failed… → bank_link.completed → payment.failed (step: sponsor_bank)
Debit failed after submission… → payment.processing → payment.failed
Refund after settlement… → payment.settled → payment.refunded
Pay-Out - settledpayment.processing → payment.settled
Pay-Out refused(none - 400 in the cashier response)
The request carries an Authorization header with a Mozarto-generated signature token. Verify it before applying any balance or state change. See Webhook Setup.

Transaction statuses#

transaction_statusPay-InPay-OutFinalMeaning
Initiated✓✓Created; identity / bank steps in progress (Pay-In) or submission in progress (Pay-Out)
Pending✓Sent to the Sponsor Bank, waiting for settlement
Processing✓Payout sent, waiting for settlement
Approved✓✓✓Funds settled
Failed✓✓✓Declined at a step (identity, screening, bank link, risk), a Sponsor Bank failure, or a technical error
Rejected✓✓Payout refused by Mozarto (closed loop, no verified bank, insufficient wallet balance)
Refunded✓✓✓A settled payment was returned
Signal risk scores are stored on the transaction and shown in the transaction grid and detail view as Customer Return Risk and Bank Return Risk.

Sandbox testing#

ItemValue
Test identityLeslie Knope - DOB 1975-01-18, phone +12345678909, SSN 123456789
Bank loginInstitution Tartan Bank or First Platypus Bank, username user_good, password pass_good, OTP 1234
Forced bank-link failureInstitution First Gingham Credit Union returns INSTANT_MATCH_FAILED (tests bank_link.failed)
Signal risk scoreSandbox scores are random unless you use these amounts: 3.53 → low risk (score 10, expect ACCEPT), 12.17 → score 60, 27.53 → high risk (score 90, expect risk_check.declined)
SettlementThe sandbox does not settle payments by itself - a Pay-In or Pay-Out stays Pending / Processing until Mozarto simulates the Sponsor Bank outcome (settled, failed, refunded) on request
Gated products: PayModum Monitor (watchlist screening) and Signal rulesets must be enabled for your environment.

Error codes#

Mozarto errorCodeWhen
PSP_NOT_CONFIGUREDRequired PayModum or Sponsor Bank settings are missing for this brand
Step-level declines (identity, screening, bank link, risk, settlement) are reported through the webhook event catalog; payout refusals are returned in the cashier response. For the full list of errorCode values and retryability guidance, see Errors.
Modified at 2026-11-02 13:21:22
Previous
PawaPay
Next
PayOne
Built with