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 onboards once and the same onboarding covers both In-Store Acceptance and Online Payments. 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. If your merchants already complete onboarding inside the Tapaya Terminal app, you can skip this page.
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.
To take online payments after onboarding, also enable Checkout in Checkout settings. 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.
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 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 '{
"mcc": "5411",
"url": "https://acme.example.com",
"supportPhone": "+420123456789",
"statementDescriptor": "ACME CORP"
}'Parameters:
| Field | Type | Required | Description |
|---|---|---|---|
mcc | string | ✓ | Four-digit Merchant Category Code. |
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",
"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 |
|---|---|---|---|
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"
}