Skip to main content
If your platform moves money on behalf of your own customers (individuals or companies), register each customer as a merchant under your VelaFi account. Each merchant passes its own KYC (individuals) or KYB (businesses) verification and gets its own Merchant ID (MID). Once the merchant is approved and its currency accounts are active, you pass that MID on every payment call you make for that customer.

How it works

  1. Create the merchant. VelaFi returns a merchantId and a hosted kycLink.
  2. Send your customer to the kycLink to complete KYC or KYB.
  3. Poll the merchant’s status until it is 2 (Normal).
  4. Activate a currency account (channel) for each currency the customer needs.
  5. Optionally create virtual accounts so each of the customer’s payers gets its own deposit details.
  6. Use the merchantId in every order, payout, transfer and query for that customer.

Before you start

  • API access, an API key with an IP whitelist, and a token. See Authentication. All calls on this page go from your server, with the X-BH-TOKEN header.
  • Your own account approved. Merchants you create sit under your VelaFi account. See Merchants for the multi-merchant model.
  • The customer’s data ready. Decide whether each customer is INDIVIDUAL or BUSINESS, and collect a merchant name and an email address for each.
  • A page to return users to. You pass it as callbackUrl. For individual verification, VelaFi redirects the user’s browser to this URL when they finish the hosted flow.

Step by step

1

Create the merchant

Call Create Merchant (POST /v2/merchants) with merchantName, email, merchantType (INDIVIDUAL or BUSINESS) and callbackUrl. Send industryType too (and industryTypeRemark when it is other). For individuals, flow selects the KYC flow (PROFESSIONALS by default, or CONSUMERS), and languageCode sets the language of the hosted page (en, es, pt, zh).
Store merchantId against the customer in your system right away. The merchant exists from this point, even before verification.Common rejections:
Creating a merchant is not idempotent. If the call times out, do not create the merchant again with different details. List your merchants filtered by the email you sent (see step 3) to find out whether it was created.
2

Send the customer to the verification link

Redirect the customer’s browser to kycLink, or open it in an iframe in your app. Individuals complete KYC; businesses complete KYB. See Create a Merchant for both display options.The link is time-limited. If the customer did not finish, or the link expired, get a new one by calling POST /v2/merchants again with the existing merchantId, the same merchantType you used at creation, and callbackUrl:
This does not create a second merchant. It fails with -5062 while the merchant’s verification is under review and with -5063 once it has been approved.
Reaching your callbackUrl only means the customer left the hosted flow. It does not mean they were approved. Always check the status in the next step.
3

Check the merchant status

Call List Merchants (GET /v2/merchants) and read status and rejectReason. Pass status=-1: without it the list returns only approved merchants. Filter with email or merchantName to find one merchant.
There is no webhook for merchant verification. Poll at a modest interval, for example every few minutes while the customer is onboarding and less often after that.
4

Activate currency accounts

For each currency the customer needs, call POST /v2/merchant/accounts with merchantId, fiat and trench (the channel name), plus the channel’s fieldList. The request differs by merchant type:
Handle the returned status:Then poll GET /v2/merchant/accounts?merchantId=100001 until the channel shows status: 2. Each record also returns the channel’s paymentId, which you need for virtual accounts, payouts and orders.Some channels have extra requirements. BRL Pix - Woovi needs a liveness check first for individuals (Get Woovi Liveness URL) and full company and UBO data for businesses. Documents must be uploaded with Upload File. See Activate a Merchant Account for every channel.Common rejections: -5073 (the merchant has not passed KYC yet), -5074 (already active), -5062 (activation already pending), -5079 (no activation permission for this channel), -4010 (a required fieldList field is missing or invalid).
5

Optional: create virtual accounts

If the customer collects from many payers, give each payer its own deposit details with Create Virtual Accounts (POST /v2/merchant/virtual/accounts). Send merchantId, fiat, the channel’s paymentId and an alias of letters and digits. Virtual accounts are available for MXN, ARS, BRL and COP, and the currency account must already be active.Read the deposit details with List Virtual Accounts. Deposits to a virtual account carry its alias as depositAlias. See Collect local payments with virtual accounts for the full collection flow.

Use the merchant ID in every other call

The merchantId decides whose balance, limits and accounts a call uses. Send the customer’s MID, not your own, on every call you make for that customer: Keep a one-to-one mapping between your customer ID and the VelaFi MID, and never let a customer-supplied value choose the MID.

Webhooks to handle

Merchant verification and channel activation have no webhook. Poll GET /v2/merchants and GET /v2/merchant/accounts as described above. Webhooks are registered per VelaFi account, not per merchant: one registration per event type receives events for all of your merchants. Order, funding, crypto withdrawal and stablecoin payment events carry a merchantId, so route them by it. For events without one, look up the record by its ID. See Webhook Setup.

Handle failures

  • Verification rejected (status: 3). Show rejectReason to your customer, then request a new link with the same merchantId and merchantType.
  • Customer abandons the flow (status: 4). Send a reminder with a fresh link. Do not create a new merchant; the name and email are already taken by the first one.
  • Activation failed (status: 3). Read failReason in the activation response or in List Merchant Accounts. Fix the fieldList data or contact VelaFi.
  • Activation pending for a long time. Pending channels depend on the provider. Keep polling and contact VelaFi if the channel does not become active.
  • Timeouts and outcome-unknown errors (-1001, -1006, -1007). The merchant or channel may have been created. Check with List Merchants or List Merchant Accounts before you call again. See Error Codes.

Reconcile

  • GET /v2/merchants with status=-1 is the source of truth for verification status and for each merchant’s daily and monthly limit usage.
  • GET /v2/merchant/accounts is the source of truth for which channels are active, their paymentId, balance, and monthly buy/sell limits.
Run a periodic job that compares your customer records with both lists, so a customer never stays stuck in a state your system does not know about.

Test in the sandbox

Your sandbox account comes with pre-configured test merchants, and no real KYC/KYB takes place in the sandbox. Use those merchants to test activation results, virtual accounts and the payment flows that follow. Write your status handling against every status code in the tables above, because you cannot make a real reviewer approve or reject a sandbox merchant. See Sandbox.

Go-live checklist

  • Store merchantId as soon as POST /v2/merchants returns, and map it one-to-one to your customer.
  • Handle every merchant status (1, 2, 3, 4) and every activation status (0 to 4), including verifyLink redirects.
  • Poll with status=-1, so merchants that are not approved yet are not missing from your results.
  • Re-request expired links with the existing merchantId and merchantType instead of creating a duplicate merchant.
  • Wait for the channel to show status: 2 before you create virtual accounts or send payments for that currency.
  • Pass the customer’s MID on every downstream call, and route webhook events by merchantId.
Then work through the shared go-live checklist.