Use the marketplace onboarding flow to connect a submerchant to your xMoney account and send them to a hosted onboarding experience at dashboard.xmoney.com.
Your marketplace creates a short-lived, signed redirect URL on its backend. The submerchant follows the URL, creates or connects an xMoney account, and provides their business and compliance information directly to xMoney. Your marketplace does not collect or send KYB documents through this flow.
- Your backend assigns a stable internal
merchantIdto the submerchant. - Your backend creates and signs an xMoney Connect URL.
- Your application redirects the submerchant's browser to the signed URL.
- xMoney validates the signature and starts a secure browser session.
- The submerchant creates an account or signs in to an existing account.
- The submerchant completes the hosted business onboarding flow.
- Your backend polls the onboarding status using the same
merchantId. xMoney does not send marketplace onboarding-status webhooks.
The onboarding form and all KYB data collection are hosted by xMoney. Do not include business data, personal data, or documents in the redirect URL.
Contact your xMoney representative to receive the credentials for your marketplace:
| Value | Purpose |
|---|---|
slug | Public identifier used in your Connect URL, for example acme-marketplace. |
signingSecret | Shared secret used by your backend to sign redirect URLs. |
keyId | Username for onboarding-status polling. |
pollingSecret | Password for onboarding-status polling. |
Keep signingSecret and pollingSecret in a secret manager and use them only from your backend. Never expose them in browser code, mobile applications, client-side logs, or public repositories.
Confirm the production and test dashboard base URLs with your xMoney representative before integrating.
The production redirect URL has this format:
https://dashboard.xmoney.com/connect/{slug}?merchantId={MERCHANT_ID}×tamp={ISO8601_UTC}&nonce={NONCE}&signature={SIGNATURE}| Parameter | Required | Rules |
|---|---|---|
slug | Yes | Your xMoney-provisioned marketplace identifier. Lowercase letters, numbers, and hyphens only; 2–64 characters. |
merchantId | Yes | Your stable internal identifier for the submerchant; maximum 191 characters. |
timestamp | Yes | Current UTC time in ISO 8601 format. Use YYYY-MM-DDTHH:mm:ssZ. The URL is accepted for 15 minutes. |
nonce | Yes | A cryptographically random, one-time value. Use 8–128 letters, numbers, underscores, or hyphens. |
signature | Yes | A base64url-encoded HMAC-SHA256 signature of the complete URL without the signature parameter. |
Use a new timestamp and nonce every time you create a redirect, including when retrying a failed or expired redirect. Keep your server clock synchronized with UTC.
First, construct the complete URL without signature. This unsigned URL is the payload:
https://dashboard.xmoney.com/connect/acme-marketplace?merchantId=merchant-123×tamp=2026-09-03T10:15:00Z&nonce=I6d9jK2L0mN4pQ8RThen compute:
signature = base64url(
HMAC-SHA256(
key = signingSecret,
message = unsignedUrl
)
)Append the result as the final signature query parameter.
Query parameter order and encoding are part of the signature. Sign the exact URL string that you redirect the browser to, before appending signature. Do not parse, reorder, decode, or re-encode the URL after signing it.
Use the recommended query parameter order: merchantId, timestamp, then nonce.
These examples use only standard libraries.
const crypto = require('crypto');
function createSubmerchantOnboardingUrl({
dashboardBaseUrl = 'https://dashboard.xmoney.com',
slug,
signingSecret,
merchantId,
}) {
const timestamp = new Date().toISOString().replace(/\.\d{3}Z$/, 'Z');
const nonce = crypto.randomBytes(16).toString('base64url');
const payloadUrl = new URL(`${dashboardBaseUrl}/connect/${slug}`);
payloadUrl.searchParams.set('merchantId', merchantId);
payloadUrl.searchParams.set('timestamp', timestamp);
payloadUrl.searchParams.set('nonce', nonce);
const payload = payloadUrl.toString();
const signature = crypto
.createHmac('sha256', signingSecret)
.update(payload, 'utf8')
.digest('base64url');
return `${payload}&signature=${signature}`;
}Call the relevant function on your backend and redirect the browser to the returned URL.
Return the signed URL from your backend and navigate the submerchant's browser to it using a full-page redirect.
Do not generate the signature in frontend code. A frontend application can request a newly signed URL from your backend immediately before redirecting:
const response = await fetch('/api/xmoney/onboarding-url', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ merchantId: 'merchant-123' }),
});
const { redirectUrl } = await response.json();
window.location.assign(redirectUrl);A valid redirect starts an xMoney browser session for up to 24 hours. If the link is not validated within 15 minutes, or if its nonce was already used, generate a new signed URL.
After xMoney validates the redirect, the submerchant can create a new xMoney account or connect an existing account. New accounts must verify their email address.
The hosted onboarding flow then collects:
- legal business and contact information;
- business activity, ownership, and legal-representative information;
- website and processing information;
- required company and identity documents;
- payout bank-account information; and
- final declarations and submission for review.
Referred submerchants must apply for FIAT processing. After submission, xMoney reviews the business and may request additional information before activation.
xMoney does not send webhook notifications when a referred submerchant's onboarding status changes. Poll this endpoint from your backend to retrieve the latest status.
Use the marketplace's internal merchantId to retrieve the current high-level onboarding status:
GET {partnersApiBaseUrl}/business-referrals/{merchantId}/onboarding-status
Authorization: Basic base64(keyId:pollingSecret)
Accept: application/jsonFor example:
curl --user "$XMONEY_KEY_ID:$XMONEY_POLLING_SECRET" \
--header "Accept: application/json" \
"$XMONEY_PARTNERS_API_URL/business-referrals/merchant-123/onboarding-status"A successful response has this shape:
{
"merchantId": "merchant-123",
"xmoneyMerchantId": 7291,
"status": "kyb_review_in_progress",
"kybDecisionStatus": "pending",
"contractStatus": null
}The endpoint returns only referrals associated with the business represented by your credentials. A merchantId belonging to another marketplace is not accessible.
| Field | Type | Description |
|---|---|---|
merchantId | string | Your parent-scoped merchant identifier from the signed redirect. |
xmoneyMerchantId | number or null | The xMoney business identifier. It remains null until the submerchant submits a business application. |
status | string | The current overall onboarding lifecycle status. |
kybDecisionStatus | string or null | The current KYB decision: pending, success, failed, or null when no decision is available. |
contractStatus | string or null | The contract delivery status: sent, completed, or null. A declined contract is represented by status: contract_declined. |
| Status | Meaning |
|---|---|
redirect_received | The signed redirect was validated, but the submerchant has not connected an account. |
application_started | An account is connected, but the FIAT business application has not been submitted. |
ubo_kyc_pending | At least one ultimate beneficial owner still needs to complete KYC. |
kyb_review_in_progress | xMoney is reviewing the submitted FIAT business application. |
kyb_approved | KYB is approved and the application has reached the contract stage. |
kyb_rejected | The FIAT business application was rejected. |
contract_sent | The contract was sent for signature. |
contract_declined | The contract was declined. |
contract_signed | The contract was signed and account activation is pending. |
account_active | The FIAT onboarding is complete and the account is active. |
Before the submerchant first opens and validates a signed redirect URL, xMoney has no record of the merchantId. Polling that ID returns 404 Not Found.
Treat the other common responses as follows:
| HTTP status | Meaning |
|---|---|
200 OK | Status returned successfully. |
401 Unauthorized | The polling credentials are missing or invalid. |
404 Not Found | The merchantId is unknown to this marketplace. |
Continue polling while the onboarding process is progressing and stop after account_active. Coordinate any follow-up for kyb_rejected or contract_declined with xMoney. Use exponential backoff and avoid polling more often than the interval agreed with xMoney.
The polling endpoint uses HTTP Basic authentication:
- Set the username to your
keyId. - Set the password to your
pollingSecret. - Send credentials only over HTTPS.
xMoney validates that the credential is active and verifies the polling secret securely. If an IP allowlist is configured for your credential, requests must also originate from an allowed IP address. Invalid credentials and disallowed IP addresses return 401 Unauthorized.
- Create signed URLs only on your backend.
- Store
signingSecretandpollingSecretin a secret manager. - Generate a cryptographically random nonce for every redirect.
- Never reuse a nonce, even for the same
merchantId. - Generate the timestamp immediately before redirecting.
- Keep the unsigned URL byte-for-byte identical after signing.
- Use HTTPS in production.
- Do not log secrets or complete signed URLs.
- Do not place personal, business, or KYB data in query parameters.
- Scope polling results by the
merchantIdstored in your own system.
For security, invalid, expired, and reused redirects display a generic invalid-link response. Check the following before contacting xMoney:
| Problem | What to check |
|---|---|
| Invalid signature | Confirm that both systems use the same signingSecret, HMAC-SHA256, UTF-8 input, and unpadded base64url output. |
| Invalid signature | Confirm that you signed the complete URL without signature and did not alter its parameter order or encoding afterward. |
| Expired link | Generate the timestamp at redirect time and confirm that your server clock is synchronized. |
| Reused link | Generate a fresh nonce and a new signature for every redirect attempt. |
| Unknown marketplace | Confirm that the URL path uses the exact lowercase slug provisioned by xMoney. |
| Missing merchant | Include a non-empty merchantId that is no longer than 191 characters. |
When requesting support, share the assigned slug, environment, your merchantId, and the approximate UTC time of the failure. Do not send your signing or polling secrets.