Merchant Onboarding API
Create merchants and submit or invite them to onboarding through the Tapaya Platform API.
All requests on this page use your Server Secret Token. See Authentication.
One onboarding for In-Store and Online
A merchant can request In-Store Acceptance, Online Payments, or both in one onboarding application. This page applies to every integration: the Accept SDK, the Tapaya Terminal app, and Checkout. Use it to create and manage merchants through the API instead of the Tapaya Platform UI. Request the payment capabilities the merchant needs. An in-store approval alone does not enable online payments.
Creating a merchant with POST /integrator/merchant, or with POST /merchant/auth/register in an
Accept SDK integration,
creates its account, but the merchant cannot process live payments in store or online until onboarding is complete.
For online payments, request the Checkout capability and wait for online processor approval and gateway setup. Merchants appear automatically in Checkout settings, where you can check readiness and configure keys and wallets. Tapaya supports several onboarding experiences; all can be managed from the Tapaya Platform UI and automated where appropriate.
| Flow | When to use it | API entry point |
|---|---|---|
| Tapaya Platform UI | Your operations team completes onboarding on the merchant's behalf. | Create or select the merchant in the Tapaya Platform UI and open the hosted onboarding there. |
| Your own UI | You collect and validate onboarding information in your product. | Validate sections with POST /integrator/merchant/onboarding/validate/*, then submit with POST /integrator/merchant/onboarding. Detailed below. |
| Email invite | A known merchant receives a single-use invitation to self-onboard. | Send an invite with POST /integrator/merchant/send-registration-invite; include merchantToken to bind the invite to an existing merchant shell, then list or revoke it through /integrator/merchant/invites. |
| Campaign link | Multiple or not-yet-known merchants use a reusable self-registration link. | Create a link with POST /integrator/merchant/reusable-registration-invites; list or revoke links through the same resource. |
For a detailed comparison of these flows, see the Merchant Onboarding guide.
Request online payment capabilities
POST /integrator/merchant/onboarding requires capability. Use the same capability when validating the business profile:
| Value | Capability | Channel details |
|---|---|---|
1 | Both | Supply terminal and online. Each channel requires its own approval. |
2 | Terminals | Supply terminal for in-store payments. |
3 | Checkout | Supply online for online payments. No terminal is required. |
For Checkout, add the following top-level fields alongside the merchant's identity, address, shared business, and KYB data. The same channel fields apply to POST /integrator/merchant/onboarding/validate/business:
{
"capability": 3,
"online": {
"mcc": "5411",
"statementDescriptor": "ACME CORP",
"productDescription": "Groceries sold online",
"averageItemValue": 2500,
"expectedMonthlyTurnover": 500000,
"url": "https://www.acme.example.com",
"purchaseChargeTiming": 1,
"averageDeliveryDays": 2,
"topCountries": [{ "countryId": 1, "percentage": 100 }]
}
}Amounts are in minor currency units. The online website must use HTTP or HTTPS and its hostname must contain www. statementDescriptor is 5 to 22 characters. purchaseChargeTiming is 1 for order placed, 2 for shipped, or 3 for received. averageDeliveryDays is 0 to 999. Supply one to four unique topCountries whose percentages total 100.
Keep shared support and financial details in business. In channel-section mode, put MCC, statement descriptor, product description, and transaction estimates in the relevant terminal or online object. Validate the payload before submitting onboarding, and resolve the returned channel-specific field errors.
Invite a Merchant to Complete Hosted Onboarding
Use this flow when Tapaya should host the KYB form, but you still want to control merchant creation from your backend.
Recommended when you own merchantToken
If your system owns the merchant identifier used later by the SDK or your back office, first create the merchant
shell with POST /merchant/auth/register or POST /integrator/merchant, then call
POST /integrator/merchant/send-registration-invite with the same merchantToken. This keeps the hosted
onboarding attached to that merchant instead of creating a second one.
The recommended sequence is:
- Create the merchant shell:
POST /merchant/auth/register, orPOST /integrator/merchant
- Send the hosted onboarding invite with
POST /integrator/merchant/send-registration-invite - Share the returned
registrationUrlwith the merchant if needed, and let them complete the Tapaya-hosted form - Poll merchant readiness through
GET /integrator/merchant/{merchantId}/status
Endpoint: POST /integrator/merchant/send-registration-invite
curl -X 'POST' 'https://api.tapaya.com/integrator/merchant/send-registration-invite' \
-H 'Content-Type: application/json' \
-H 'Authorization: REPLACE_ME' \
-d '{
"email": "admin@acme.com",
"merchantToken": "unique_merchant_id_from_your_db"
}'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
email | string | ✓ | Email address that should receive the hosted onboarding link. |
merchantToken | string | Existing merchant token to bind the invite to. Use this when you already created the merchant shell and want the hosted onboarding to fill that same merchant. If omitted, completing the invite creates a new merchant. |
Responses:
| Code | Description |
|---|---|
200 | Invite created. Response includes registrationUrl |
400 | Request validation error |
401 | Unauthorized |
404 | Organization or merchant not found |
409 | Conflict |
Response body:
{
"registrationUrl": "https://platform.tapaya.com/invite-merchant?token=...&merchantToken=unique_merchant_id_from_your_db"
}Tapaya also attempts to email this link. Email delivery is best-effort, so always treat the returned
registrationUrl as the source of truth for your UI and support tooling.
Do not confuse this with merchant-user invite
POST /integrator/merchant/{merchantId}/invite is a different flow. It invites a platform user to access an
already-existing merchant account. It does not start KYB onboarding and does not create or update a merchant
profile.
Submit Onboarding through the API
If you want to collect onboarding information in your own product instead of sending merchants to the Tapaya Platform, submit it directly. Validate each section as the merchant fills it in with the validate/* endpoints below, then submit everything in one call, which creates the merchant and its onboarding profile together, and registers it with your organization's preferred payment processor.
Merchant consent and privacy notice
Before submitting onboarding details through the API, you must obtain the merchant's consent to the Tapaya Integrators Terms and Conditions and Tapaya Privacy Policy. Add a checkbox to your onboarding form that links to both documents, or link to the Tapaya documents from the terms text to which the merchant consents. You must also list Tapaya as a data processor in your own privacy policy.
Merchant not created on failure
POST /integrator/merchant/onboarding creates the merchant and submits onboarding in a single call. If the
onboarding data is invalid, it returns 422 with field-level errors and no merchant is created; there is no
partially-onboarded merchant to clean up or resume.
Validate Identity
Endpoint: POST /integrator/merchant/onboarding/validate/identity
curl -X 'POST' 'https://api.tapaya.com/integrator/merchant/onboarding/validate/identity' \
-H 'Content-Type: application/json' \
-H 'Authorization: REPLACE_ME' \
-d '{
"legalName": "Acme Corp s.r.o.",
"businessTypeId": 2,
"email": "admin@acme.com",
"registrationNumber": "12345678",
"vatNumber": "CZ12345678",
"incorporationDate": "2018-04-01"
}'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
legalName | string | ✓ | Legal name of the business or individual account holder. |
businessTypeId | int | ✓ | Type of business entity (BusinessTypeEnum). |
email | string | ✓ | Contact email address. |
registrationNumber | string | ✓ | Official business registration number. Checked for duplicates within your |
| organization. | |||
vatNumber | string | VAT registration number, if applicable. | |
incorporationDate | date | Date the business was legally incorporated (YYYY-MM-DD). |
Response body:
{
"valid": true,
"errors": []
}A registrationNumber already used by another merchant in your organization comes back as a valid: false
error with code: "DUPLICATE_REGISTRATION_NUMBER" rather than a 409; this endpoint always returns 200.
Validate Address
Endpoint: POST /integrator/merchant/onboarding/validate/address
curl -X 'POST' 'https://api.tapaya.com/integrator/merchant/onboarding/validate/address' \
-H 'Content-Type: application/json' \
-H 'Authorization: REPLACE_ME' \
-d '{
"line1": "Wenceslas Square 1",
"city": "Prague",
"postalCode": "11000",
"countryId": 1
}'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
line1 | string | ✓ | First line of the street address. |
line2 | string | Second line of the street address, if applicable. | |
city | string | ✓ | City name. |
postalCode | string | ✓ | Postal or ZIP code. |
state | string | State or region, if applicable. | |
countryId | int | ✓ | Country (CountryEnum). |
Response body: same {valid, errors} shape as Validate Identity.
Validate Business Profile
Endpoint: POST /integrator/merchant/onboarding/validate/business
curl -X 'POST' 'https://api.tapaya.com/integrator/merchant/onboarding/validate/business' \
-H 'Content-Type: application/json' \
-H 'Authorization: REPLACE_ME' \
-d '{
"capability": 2,
"mcc": "5411",
"url": "https://acme.example.com",
"supportPhone": "+420123456789",
"statementDescriptor": "ACME CORP"
}'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
capability | int | ✓ | Use the capability you will submit for onboarding. For Checkout or Both, supply the channel details. |
mcc | string | ✓ | Four-digit Merchant Category Code. In channel-section mode, use terminal.mcc or online.mcc. |
url | string | Business website URL. Either url or productDescription is required. | |
productDescription | string | Description of products or services. Either url or productDescription is | |
| required. | |||
supportPhone | string | ✓ | Customer support phone number, in E.164 format. |
statementDescriptor | string | ✓ | Text shown on customer bank statements (1–22 characters). |
averageItemValue | long | Average transaction value, in minor currency units. | |
expectedMonthlyTurnover | long | Expected monthly revenue, in minor currency units. | |
numberOfEmployees | int | Number of employees at the business. | |
annualTurnover | long | Annual revenue, in minor currency units. | |
balanceSheetTotal | long | Total balance sheet value, in minor currency units. |
Response body: same {valid, errors} shape as Validate Identity.
Validate KYB
Endpoint: POST /integrator/merchant/onboarding/validate/kyb
Provide exactly one of individual (sole trader / self-employed) or company. For a company, list every
owner, director, and authorized signatory in people.
curl -X 'POST' 'https://api.tapaya.com/integrator/merchant/onboarding/validate/kyb' \
-H 'Content-Type: application/json' \
-H 'Authorization: REPLACE_ME' \
-d '{
"businessTypeId": 2,
"bankAccount": {
"iban": "CZ6508000000192000145399",
"bic": "GIBACZPX",
"currencyId": 1,
"beneficiaryName": "Acme Corp s.r.o."
},
"company": {
"name": "Acme Corp s.r.o.",
"registrationNumber": "12345678",
"people": [
{
"email": "jane@acme.com",
"firstName": "Jane",
"lastName": "Doe",
"role": {
"isOwner": true,
"isAuthorizedSignatory": true
}
}
]
}
}'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
businessTypeId | int | Type of business entity (BusinessTypeEnum); determines whether individual or | |
company fields are required. | |||
bankAccount | object | Payout bank account (account number/IBAN + BIC, currency, beneficiary and bank | |
| address). | |||
individual | object | Individual owner details, for sole traders. Mutually exclusive with company. | |
company | object | Company details, including a people array of owners, directors, and authorized | |
signatories, plus an optional verificationDocument. Mutually exclusive with individual. |
Each person in people (and individual) carries role.isOwner / isDirector / isRepresentative /
isAuthorizedSignatory flags, plus optional identity fields (dateOfBirth, nationalityCountryId,
officialIdType/officialIdNumber, address, ownershipPercentage, verificationDocuments). A person entry
must be either invite-only or fully detailed; partially filled people are rejected. There are two ways to submit
a person:
- Invite-only: submit just
emailand arole. The person receives an email with instructions to complete their own personal details and identity verification directly, including uploading their own ID document; you don't need to collect anything else for them, and no document upload is required on your side. - Fully detailed: submit all of the person's personal details (name, date of birth, official ID, address, etc.) yourself. In this case you must also upload an ID document for that person; this is required, not optional, for every fully-detailed person.
Documents are uploaded after the merchant exists, because the document upload
endpoint needs the merchantId returned by Create Merchant with
Onboarding. Each person's upload is matched to them by
relatedOfficialIdNumber. The optional verificationDocuments.identityDocument,
verificationDocuments.additionalDocument, and company.verificationDocument fields each take a
{frontFileId, backFileId} object and can only reference files that were already uploaded, so omit them when
creating a new merchant.
Regardless of how many people are invite-only vs. fully detailed, you must always upload the company's registration/incorporation document before the merchant can be submitted for KYC review.
Response body: same {valid, errors} shape as Validate Identity.
Create Merchant with Onboarding
Submits everything from the previous four steps in one call, creates the merchant, and registers it with your organization's preferred payment processor.
Endpoint: POST /integrator/merchant/onboarding
curl -X 'POST' 'https://api.tapaya.com/integrator/merchant/onboarding' \
-H 'Content-Type: application/json' \
-H 'Authorization: REPLACE_ME' \
-d '{
"name": "Acme Corp",
"capability": 2,
"merchantToken": "unique_merchant_id_from_your_db",
"identity": {
"legalName": "Acme Corp s.r.o.",
"businessTypeId": 2,
"email": "admin@acme.com",
"registrationNumber": "12345678",
"vatNumber": "CZ12345678"
},
"address": {
"line1": "Wenceslas Square 1",
"city": "Prague",
"postalCode": "11000",
"countryId": 1
},
"business": {
"mcc": "5411",
"url": "https://acme.example.com",
"supportPhone": "+420123456789",
"statementDescriptor": "ACME CORP"
},
"kyb": {
"bankAccount": {
"iban": "CZ6508000000192000145399",
"bic": "GIBACZPX",
"currencyId": 1,
"beneficiaryName": "Acme Corp s.r.o."
},
"company": {
"people": [
{
"email": "jane@acme.com",
"firstName": "Jane",
"lastName": "Doe",
"role": {
"isOwner": true,
"isAuthorizedSignatory": true
}
}
]
}
}
}'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
capability | int | ✓ | 1 for Both, 2 for Terminals, or 3 for Checkout. See online payment capabilities. |
terminal | object | By capability | Terminal channel details for Terminals or Both. |
online | object | By capability | Online channel details for Checkout or Both. |
name | string | ✓ | The name of the merchant. |
merchantToken | string | A unique, stable identifier from your system. If not provided, a random token is | |
| generated. | |||
identity | object | ✓ | Same shape as Validate Identity. |
address | object | ✓ | Same shape as Validate Address. |
business | object | ✓ | Same shape as Validate Business Profile. |
kyb | object | ✓ | Same shape as Validate KYB. |
Responses:
| Code | Description |
|---|---|
201 | Merchant created and onboarding submitted |
422 | Onboarding data invalid, see errors; merchant is not created |
Response body (201):
{
"merchantId": "018f8f2a-3b1e-7c2a-9f1a-2e6a1b7c4d3e",
"merchantToken": "unique_merchant_id_from_your_db",
"name": "Acme Corp",
"email": "admin@acme.com",
"processors": [
{
"processorId": 5,
"registered": true,
"onboardingUrl": null
}
]
}onboardingUrl is populated when the processor requires the merchant to complete an additional hosted
onboarding flow (e.g. identity verification) before it can process live payments.
Response body (422):
{
"errors": [
{
"step": "identity",
"field": "registrationNumber",
"message": "A merchant with this registration number is already onboarded under this integrator (merchantId: 018f8f2a-3b1e-7c2a-9f1a-2e6a1b7c4d3e).",
"code": "DUPLICATE_REGISTRATION_NUMBER"
}
]
}Upload a Person's ID Document
Required for every fully-detailed person in kyb.company.people / kyb.individual (see Validate
KYB); invite-only people upload their own instead, via the emailed link.
Endpoint: POST /integrator/merchant/{merchantId}/document
Request body is multipart/form-data, not JSON.
curl -X 'POST' 'https://api.tapaya.com/integrator/merchant/018f8f2a-3b1e-7c2a-9f1a-2e6a1b7c4d3e/document' \
-H 'Authorization: REPLACE_ME' \
-F 'paymentProcessorId=5' \
-F 'documentType=2' \
-F 'relatedOfficialIdNumber=123456789' \
-F 'frontFile=@./jane-doe-id-front.jpg' \
-F 'backFile=@./jane-doe-id-back.jpg'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
paymentProcessorId | int | ✓ | Always 5. |
documentType | int | ✓ | Type of document (DocumentTypeEnum: 1 Other, 2 Id, 3 Address, 4 Company, |
5 BankStatement, 6 Passport, 7 RecentFinancials). | |||
frontFile | file | ✓ | Front side of the document image. |
backFile | file | Back side of the document image, if applicable. | |
relatedOfficialIdNumber | string | The person's officialIdNumber from Validate KYB. | |
Required only when documentType is individual-bound (e.g. Id, Passport, Address); ignored otherwise. | |||
submitMerchant | boolean | Leave unset/false here: a person's ID is not the final upload of the batch. | |
Only set true on the company document upload once every person's document has been | |||
| uploaded. |
Response body (200):
{
"frontFileId": "file_1NqtHo2eZvKYlo2CZPg8Xt5h",
"backFileId": "file_1NqtHp2eZvKYlo2CRTg9Xm3k",
"uploadedAt": "2026-07-17T12:00:00Z"
}Upload the Company Document
Required exactly once per merchant. If person details were not filled in, the authorized signatory will be able to upload this using the link from the onboarding email and this endpoint does not need to be called.
Endpoint: POST /integrator/merchant/{merchantId}/document
Request body is multipart/form-data, not JSON.
curl -X 'POST' 'https://api.tapaya.com/integrator/merchant/018f8f2a-3b1e-7c2a-9f1a-2e6a1b7c4d3e/document' \
-H 'Authorization: REPLACE_ME' \
-F 'paymentProcessorId=5' \
-F 'documentType=4' \
-F 'frontFile=@./acme-corp-register-extract.pdf' \
-F 'submitMerchant=true'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
paymentProcessorId | int | ✓ | Always 5. |
documentType | int | ✓ | Always 4 (Company) for this step. |
frontFile | file | ✓ | The company's registration/incorporation document. |
submitMerchant | boolean | Set to true to trigger the processor's KYC review now that every required | |
document has been uploaded. Defaults to false. |
Response body (200):
{
"frontFileId": "file_1NqtHo2eZvKYlo2CZPg8Xt5h",
"backFileId": null,
"uploadedAt": "2026-07-17T12:00:00Z"
}