USD / US| # | Step | What happens | Merchant webhook |
|---|---|---|---|
| 1 | Identity Verification | The 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 match | identity_verification.required → identity_verification.passed / .failed / .canceled |
| 2 | AML / watchlist screening | PayModum Monitor screening, on every transaction | watchlist.failed if not cleared |
| 3 | Bank linking | The payer links their bank on a PayModum hosted page | bank_link.required → bank_link.completed / bank_link.failed |
| 4 | ACH risk decision | PayModum Signal scores the debit. ACCEPT continues; REROUTE / REVIEW decline | risk_check.declined on decline |
| 5 | Sponsor Bank debit | The payer's bank is debited through the Sponsor Bank | payment.processing → payment.settled, or payment.failed |
| # | Step | What happens | Merchant webhook |
|---|---|---|---|
| 1 | Eligibility | The customer (userId) must have an approved PayModum deposit and a verified bank on file | (refusal is returned in the cashier response) |
| 2 | Funds check | The merchant's Sponsor Bank wallet must cover the amount | (refusal is returned in the cashier response) |
| 3 | Payout | Sent from the wallet to the customer's bank - real-time (RTP) where the bank supports it, otherwise standard bank transfer / ACH | payment.processing → payment.settled, or payment.failed |
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.
| Field | Description |
|---|---|
| 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 URL | Fallback 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.
POST /v1/api/mozarto/cashierAuthentication is required on every cashier call. See Authentication. The userIdyou authenticate the payer with identifies the customer - use the sameuserIdfor every transaction of the same customer, since payouts are only allowed to a customer who deposited under thatuserId.
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.| Field | Type | Description |
|---|---|---|
pspType * | string | Always "PAYMODUM" |
type * | string | Always "PAYIN" |
baseamount * | number | Amount in the currency's main unit, up to 2 decimals (e.g. 200 = 200 USD) |
currency * | string | "USD" |
country * | string | Payer's country - full name, ISO 3166-1 alpha-2, or alpha-3 (e.g. "United States", "US"). See Country codes |
firstName * | string | Payer first name - prefills Identity Verification and is matched against a prior verification |
lastName * | string | Payer last name |
email * | string | Payer email |
phone | string | Payer phone in E.164 (e.g. "+14155550123") |
dob | string | Date of birth, YYYY-MM-DD |
ssn | string | US SSN (9 digits) - prefills the KYC data-source check |
address | string | Street address |
city | string | City |
state | string | State / region |
zipCode | string | ZIP / postal code |
merchantReference | string | Your order reference, echoed back on every webhook |
webhookUrl | string | HTTPS endpoint for this transaction's webhooks. Overrides the configured Webhook URL |
siteUrl | string | Return 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,phoneall match the verified identity. Any mismatch, or a first-time payer, runs verification (identity_verification.requiredtells you which case applied). Values are compared ignoring case and spacing, and phone numbers by digits only.
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_..."
}{
"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"
}{
"status": "success",
"message": "Successfully",
"isSuccess": true,
"data": {
"transactionId": "6a95bf514824638671769f64",
"merchantReference": "ORDER-4821",
"amount": 200,
"transaction_status": "Initiated",
"paymentUrl": "https://verify.plaid.com/verify/idv_..."
}
}| Field | Type | Description |
|---|---|---|
transactionId | string | Mozarto transaction identifier - it arrives as transaction_id on every webhook |
merchantReference | string | Your reference from the request, or an empty string |
amount | number | The transaction baseamount |
transaction_status | string | Always "Initiated" at this point |
paymentUrl | string | Redirect the payer here. It is the identity verification page, or - for a returning verified payer - the bank-linking page |
400 with the reason and the matching failure webhook is sent.POST /v1/api/mozarto/cashiertype to "PAYOUT". The payout is submitted immediately - there is no paymentUrl and no redirect.Closed loop. Authenticate with the same userIdthe 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.
| Field | Type | Description |
|---|---|---|
pspType * | string | Always "PAYMODUM" |
type * | string | Always "PAYOUT" |
baseamount * | number | Amount to send, in the currency's main unit (e.g. 200 = 200 USD) |
currency * | string | "USD" |
country * | string | Payee's country - full name, ISO 3166-1 alpha-2, or alpha-3. See Country codes |
firstName | string | Payee first name (defaults to the authenticated user's) |
lastName | string | Payee last name (defaults to the authenticated user's) |
email | string | Payee email (defaults to the authenticated user's) |
phone | string | Payee phone in E.164 |
merchantReference | string | Your reference, echoed back on every webhook |
webhookUrl | string | HTTPS endpoint for this transaction's webhooks. Overrides the configured Webhook URL |
{
"pspType": "PAYMODUM",
"type": "PAYOUT",
"baseamount": 200,
"currency": "USD",
"country": "US",
"firstName": "Leslie",
"lastName": "Knope",
"email": "leslie.knope@example.com",
"merchantReference": "PAYOUT-7723"
}{
"status": "success",
"message": "Successfully",
"isSuccess": true,
"data": {
"transactionId": "6a97e94a4608b3c3f6d46d6d",
"merchantReference": "PAYOUT-7723",
"amount": 200,
"transaction_status": "Processing"
}
}payment.processing / payment.settled follow by webhook.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
}message | transaction_status | Meaning |
|---|---|---|
Payout is only allowed to customers with an approved deposit | Rejected | This userId has never deposited with PayModum |
Payout is only allowed once a deposit from the last linked bank account is approved | Rejected | The customer's last deposit bank has no approved deposit yet (still pending, or failed) |
Last linked bank account is no longer verified | Rejected | The customer's last deposit bank is no longer verified |
Insufficient wallet balance (<balance> < <amount>) | Rejected | The Sponsor Bank Wallet does not cover the payout |
| PSP configuration / provider error | Failed | Sponsor Bank Wallet ID missing, or a provider error |
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"
}| Field | Description |
|---|---|
event | What happened - see the event catalog |
step | The flow stage: identity_verification, watchlist, bank_link, signal, sponsor_bank, settlement, or initiation |
psp | Always "PAYMODUM" |
timestamp | ISO 8601 time the event was emitted |
data | Step-specific detail (see catalog) |
transaction_id | Mozarto transaction identifier (transactionId in the cashier response) |
psp_transaction_id | Provider reference. Pay-In: PayModum Item id once the bank is linked. Pay-Out: the Sponsor Bank payment id. Empty before that |
user_id | The customer's userId |
status | Event outcome: success, failed, action_required, processing, or refunded |
transaction_status | The transaction's status after this event - see Transaction statuses. Use it for business logic |
amount | Transaction amount in the currency's main unit |
currency | ISO 4217 currency code |
merchantReference | Your reference from the original request, or an empty string |
event | step | status | transaction_status | data | When |
|---|---|---|---|---|---|
identity_verification.required | identity_verification | action_required | Initiated | reason, action, paymentUrl, and mismatched_fields when reason is re_verify_mismatch | Verification is needed. reason: first_time, re_verify_mismatch (details differ from the verified identity) or retry (previous attempt did not pass) |
identity_verification.passed | identity_verification | success | Initiated | idv_status, or reason: "previously_verified" | Identity verified - or verification skipped for a returning verified payer |
identity_verification.failed | identity_verification | failed | Failed | reason, idv_status | Verification declined (failed / pending_review / expired) |
identity_verification.canceled | identity_verification | failed | Failed | reason, idv_status | Verification abandoned or superseded by a newer attempt |
watchlist.failed | watchlist | failed | Failed | reason, watchlist_status | AML / watchlist screening not cleared |
bank_link.required | bank_link | action_required | Initiated | action, paymentUrl | Redirect the payer to the bank-linking page |
bank_link.completed | bank_link | success | Initiated | item_id, account_id | The payer linked their bank |
bank_link.failed | bank_link | failed | Failed | reason, error_code, error_message | Bank linking ended with an unrecoverable error |
risk_check.declined | signal | failed | Failed | reason, ruleset_result, customer_return_risk, bank_return_risk | Signal returned REROUTE / REVIEW |
payment.processing | settlement | processing | Pending (Pay-In) / Processing (Pay-Out) | checkbook_status, checkbook_id | The Sponsor Bank accepted the debit / payout and it is in flight |
payment.settled | settlement | success | Approved | checkbook_status, checkbook_id | Funds settled - final success |
payment.failed | sponsor_bank or settlement | failed | Failed | reason (+ provider), or checkbook_status, checkbook_id | The Sponsor Bank submission failed (sponsor_bank), or the payment failed / was voided / expired (settlement) |
payment.refunded | settlement | refunded | Refunded | checkbook_status, checkbook_id | A 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.| Scenario | Webhooks (in order) |
|---|---|
| Pay-In, first-time payer - settled | identity_verification.required → identity_verification.passed → bank_link.required → bank_link.completed → payment.processing → payment.settled |
| Pay-In, returning verified payer - settled | identity_verification.passed (previously_verified) → bank_link.required → bank_link.completed → payment.processing → payment.settled |
| Pay-In, identity details changed | identity_verification.required (re_verify_mismatch) → then as a first-time payer |
| Identity declined | identity_verification.required → identity_verification.failed |
| Verification abandoned / superseded | identity_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 - settled | payment.processing → payment.settled |
| Pay-Out refused | (none - 400 in the cashier response) |
Authorization header with a Mozarto-generated signature token. Verify it before applying any balance or state change. See Webhook Setup.transaction_status | Pay-In | Pay-Out | Final | Meaning |
|---|---|---|---|---|
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 |
| Item | Value |
|---|---|
| Test identity | Leslie Knope - DOB 1975-01-18, phone +12345678909, SSN 123456789 |
| Bank login | Institution Tartan Bank or First Platypus Bank, username user_good, password pass_good, OTP 1234 |
| Forced bank-link failure | Institution First Gingham Credit Union returns INSTANT_MATCH_FAILED (tests bank_link.failed) |
| Signal risk score | Sandbox 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) |
| Settlement | The 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.
Mozarto errorCode | When |
|---|---|
PSP_NOT_CONFIGURED | Required PayModum or Sponsor Bank settings are missing for this brand |
errorCode values and retryability guidance, see Errors.