Global cryptocurrency payment gateway. Supports Pay-In and Pay-Out in BTC, ETH, USDT, and other cryptocurrencies configured in your ForumPay account.Operations: Pay-In ✓ | Pay-Out ✓ | Webhook ✓
Processing: Asynchronous - redirect user to hosted page; final status via webhookFields marked with * are required.
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.
| Field | Description |
|---|
username * | ForumPay API username |
password * | ForumPay API password |
forumpayUserId * | Your ForumPay user/payer identifier - omitting this field causes ForumPay to reject all requests with "Payer ID is required" |
webhookUrl * | Your HTTPS endpoint for transaction status updates |
widgetType | ForumPay payment page mode. One of "0", "1", "2", "3". Defaults to "3" if not set. See Widget type reference below |
allowMultiplePayments | Whether the payment link stays active for repeat payments after the first success. Defaults to true (reusable link). Set to false to deactivate the link after the first successful payment |
itemName | Label shown to the payer on ForumPay's hosted page describing what they are buying. Omitted from the payment page when not set |
widgetType | Payment page collects |
|---|
"0" | Payment only |
"1" | Billing address + payment |
"2" | Billing address + shipping address + payment |
"3" (default) | Payment + email - ForumPay collects the payer's email itself |
For widgetType "0"-"2", Mozarto forwards the payer's email to ForumPay (payer_email) since the payment page does not collect it. For "3", Mozarto omits payer_email - ForumPay collects it directly on the page.
Pay-In#
POST /v1/api/mozarto/cashier
Required header: x-user-token: Bearer <user-jwt> must be sent with every Pay-In request. The value must be a valid decodable JWT - passing a plain string causes a timeout. See Authentication.
Request body#
| Field | Type | Description |
|---|
pspType * | string | Always "FORUMPAY" |
type * | string | Always "PAYIN" |
baseamount * | number | Amount as a number (e.g. 100.00) |
currency * | string | Fiat currency (e.g. "EUR", "USD") |
userId * | string | Your internal user/player identifier |
email * | string | User's email address |
country * | string | User's country - full name, ISO 3166-1 alpha-2, or alpha-3 (e.g. "Germany", "DE", "DEU"). See Country codes. Matched against the account's Processing Scope. Omit it and Mozarto geo-locates the caller's IP instead |
Example request#
{
"pspType": "FORUMPAY",
"type": "PAYIN",
"baseamount": 100.00,
"currency": "EUR",
"userId": "user_123",
"email": "player@example.com",
"country": "DE"
}
Response#
{
"status": "success",
"message": "Successfully",
"isSuccess": true,
"data": {
"url": "https://pay.forumpay.com/invoice/abc123xyz",
"transactionId": "69f332c3f6abfbeab46f98db",
"transaction_status": "Pending",
"merchantReference": "ORDER-4821",
"amount": 100
}
}
| Field | Description |
|---|
data.url | ForumPay hosted payment page - redirect the user here to select a cryptocurrency and complete payment |
data.transactionId | Mozarto transaction ID - use for status queries and to match the webhook |
data.transaction_status | Always "Pending" on creation |
data.merchantReference | The merchant reference from the request - empty string if not set |
data.amount | The requested fiat amount as a number |
The raw fields returned by ForumPay's payment-link creation (including url) are merged into data alongside the Mozarto fields above.
Open data.url in the user's browser. The user selects their cryptocurrency and completes payment on ForumPay's hosted page.
Pay-Out#
POST /v1/api/mozarto/cashier
Required header: x-user-token: Bearer <user-jwt> must be sent with every Pay-Out request. The value must be a valid decodable JWT. See Authentication.
Request body#
| Field | Type | Description |
|---|
pspType * | string | Always "FORUMPAY" |
type * | string | Always "PAYOUT" |
baseamount * | number | Pay-Out amount as a number (e.g. 200.00) |
currency * | string | Fiat currency the amount is denominated in |
userId * | string | Your internal user/player identifier |
email * | string | User's email address |
country * | string | User's country - full name, ISO 3166-1 alpha-2, or alpha-3 (e.g. "Germany", "DE", "DEU"). See Country codes. Matched against the account's Processing Scope. Omit it and Mozarto geo-locates the caller's IP instead |
preferredCrypto * | string | Cryptocurrency to send - e.g. "BTC", "ETH", "USDT", "LTC" |
walletAddress * | string | Destination wallet address for the chosen cryptocurrency |
Example request#
{
"pspType": "FORUMPAY",
"type": "PAYOUT",
"baseamount": 200.00,
"currency": "EUR",
"userId": "user_123",
"email": "player@example.com",
"country": "DE",
"preferredCrypto": "BTC",
"walletAddress": "bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"
}
Response#
{
"status": "success",
"message": "Transaction is on hold",
"isSuccess": true,
"data": {
"invoice_currency": "EUR",
"invoice_amount": "10.00",
"currency": "BTC",
"payment_source": "cash",
"wait_time": "20 minutes",
"network_processing_fee": "0.00000966",
"rate": "65419.3380",
"amount_exchange": "0.00015286",
"amount": 10,
"fast_transaction_fee": "0.00002066",
"fast_transaction_fee_currency": "BTC/kB",
"payment_id": "badd0b52-110f-4be2-af64-59d7645796af",
"reference_no": "69f332c3f6abfbeab46f98db",
"address": "btc-1eda64a85da94d71a2ac5ed84e929553",
"access_token": "<forumpay-access-token>",
"transactionId": "69f332c3f6abfbeab46f98db",
"transaction_status": "On Hold",
"merchantReference": ""
}
}
| Field | Description |
|---|
data.transactionId | Mozarto transaction ID - use for status queries |
data.payment_id | ForumPay internal payment identifier |
data.reference_no | ForumPay reference number - matches transactionId |
data.invoice_currency | The fiat currency of the original request |
data.invoice_amount | The fiat amount as a string |
data.currency | The cryptocurrency being sent (e.g. "BTC") |
data.rate | Exchange rate at time of transaction creation |
data.amount_exchange | Equivalent crypto amount to be transferred |
data.network_processing_fee | Blockchain network fee in crypto |
data.fast_transaction_fee | Optional fast transaction fee |
data.wait_time | Estimated processing time |
data.address | ForumPay internal payout address reference |
data.access_token | ForumPay session token - do not expose to end users |
data.transaction_status | Always "On Hold" on creation - the payout awaits manual approval in the Mozarto back office before ForumPay processes the transfer |
data.transactionId | Mozarto transaction ID - use for status queries and to match the webhook |
data.merchantReference | The merchant reference from the request - empty string if not set |
data.amount | The requested payout amount (fiat) as a number |
"Transaction is on hold": A message of "Transaction is on hold" with isSuccess: true means the payout was created successfully but requires manual approval in the Mozarto back office before ForumPay processes the transfer. Do not treat this as a failure. Show the user a "pending approval" message and wait for the webhook to deliver the final outcome (SUCCESS or REJECTED).
Webhook#
Mozarto calls your webhookUrl when the transaction reaches a final state - ForumPay reports the payment as confirmed or cancelled, and Mozarto then forwards a normalized notification to you. Pending states are acknowledged but not forwarded.Payload example#
{
"transaction_id": "69f332c3f6abfbeab46f98db",
"psp_transaction_id": "69f332c3f6abfbeab46f98db",
"user_id": "000000000000000000000001",
"method": "FORUMPAY_PAYIN",
"status": "confirmed",
"transaction_status": "Approved",
"message": "Crypto payment confirmed and successfully processed",
"currency": "BTC",
"confirmed": true,
"invoice_currency": "EUR",
"merchantReference": "ORDER-4821",
"amount": 100
}
| Field | Description |
|---|
transaction_id | Mozarto transaction ID - matches data.transactionId from the Pay-In/Pay-Out response |
psp_transaction_id | ForumPay reference number - matches transaction_id |
user_id | The user ID from the original transaction |
method | Transaction method - "FORUMPAY_PAYIN" or "FORUMPAY_PAYOUT". Use this to distinguish Pay-In from Pay-Out |
status | Raw ForumPay state - "confirmed" or "cancelled". Do not use for business logic |
transaction_status | Normalized Mozarto status - "Approved" or "Declined". Use this for all business logic |
message | Human-readable description of the outcome |
currency | The cryptocurrency the payment settled in (e.g. "BTC") |
confirmed | Boolean - whether ForumPay confirmed the on-chain payment |
invoice_currency | The fiat currency of the original request (e.g. "EUR") |
merchantReference | The merchant reference passed in the original request - empty string if not set |
amount | Transaction amount as a number |
Error webhook#
If the transaction fails, Mozarto forwards an error notification instead. It carries status: "error", transaction_status: "Failed", currency: "error", confirmed: false, and an additional error object with the raw ForumPay failure details:{
"transaction_id": "69f332c3f6abfbeab46f98db",
"psp_transaction_id": "69f332c3f6abfbeab46f98db",
"user_id": "000000000000000000000001",
"method": "FORUMPAY_PAYIN",
"status": "error",
"transaction_status": "Failed",
"message": "Transaction failed due to an internal error",
"currency": "error",
"confirmed": false,
"invoice_currency": "EUR",
"error": { "err": "..." },
"merchantReference": "ORDER-4821",
"amount": 100
}
Note on duplicates: ForumPay may deliver multiple webhook callbacks for the same transaction. Implement idempotency on your side - check the current state of the transaction before applying any changes. See Webhook Setup.
Error codes#
ForumPay transport failures are mapped to normalized Mozarto errorCode values. Use errorCode for programmatic handling rather than parsing raw data.err strings.Mozarto errorCode | PSP raw signal | When |
|---|
PSP_NOT_CONFIGURED | Missing credentials in Mozarto back office | username, password, or forumpayUserId not set for this brand |
INVALID_PSP_CREDENTIALS | HTTP 401 / 403, or body contains "Unauthorized" or "Invalid credentials" | API credentials are wrong or expired |
PSP_NOT_CONFIGURED | Body contains "Payer ID is required" | forumpayUserId is missing from the ForumPay configuration |
PSP_TIMEOUT | HTTP 408, or response body contains "timeout" | ForumPay did not respond in time - safe to retry |
PSP_UNAVAILABLE | HTTP 5xx | ForumPay service error - safe to retry with backoff |
PSP_RATE_LIMITED | HTTP 429 | Too many requests - retry after a delay |
UNKNOWN_PSP_ERROR | HTTP 200 with data.err or data.err_code set | ForumPay returned a business-level rejection (e.g. invalid wallet address, unsupported currency pair) - check data.err and data.err_code for the raw ForumPay reason |
UNKNOWN_PSP_ERROR | Any other unrecognised response | Fallback - check data for the raw ForumPay response and contact support if it persists |
Business rejections: ForumPay may return HTTP 200 with data.err and data.err_code fields set when a transaction is rejected at the application layer (for example, an unsupported cryptocurrency or an invalid wallet address). These produce UNKNOWN_PSP_ERROR because the HTTP status is not available at that boundary. Inspect data.err_code for the ForumPay-specific reason.
For the full list of errorCode values and retryability guidance, see Errors. Modified at 2026-11-02 13:20:05