Create an API credential
Merchant Portal → Merchant API
After creation, the Key ID (vmk_...) and secret are shown. The secret is shown once only, so store it in a secure secret manager.
The current V-REC platform is split into four API layers: Merchant Server API, Corporate / Partner Payout API, authenticated User Session API, and the internal SAKURA Connected Apps integration. User provisioning, KYC, cards, payout creation and Tenant Funding are intentionally separated by trust boundary.
# Merchant Server API
X-VREC-Merchant-Key: vmk_...
X-VREC-Timestamp: ...
X-VREC-Nonce: ...
X-VREC-Signature: ...
# Corporate / Partner Payout API
X-VREC-Key: vrec_...
X-VREC-Timestamp: ...
X-VREC-Nonce: ...
X-VREC-Signature: ...Before using the Merchant Server API, create an API credential in Merchant Portal, then configure a webhook URL and webhook secret. The API secret and webhook secret are different credentials.
Merchant Portal → Merchant API
After creation, the Key ID (vmk_...) and secret are shown. The secret is shown once only, so store it in a secure secret manager.
Merchant Portal → Merchant API → Merchant Webhook
Register an HTTPS receiver URL and a webhook secret of at least 32 characters. After saving, verify the CONFIGURED status and the stored URL.
webhook.test
Press “Send test webhook” in Merchant Portal and confirm DELIVERED with an HTTP 2xx response in the delivery history. Delivery is processed by the scheduler.
X-VREC-Merchant-Key: vmk_...
X-VREC-Timestamp: UNIX timestamp
X-VREC-Nonce: unique random string
X-VREC-Signature: HMAC-SHA256(...)X-VREC-Event: user.registered | user.kyc.updated | tenant.funding.* | webhook.test
X-VREC-Delivery: mwd_...
X-VREC-Timestamp: UNIX timestamp
X-VREC-Signature: HMAC-SHA256(timestamp + "\n" + delivery + "\n" + event + "\n" + SHA256(raw_body))Verify the signature against the unmodified raw body and return HTTP 2xx when the event is accepted.
Do not mix corporate backend APIs, cardholder session APIs and the internal V-REC ↔ SAKURA integration.
/api/merchant/v1/*
Provision users, manage status, monitor KYC, read masked cards, Merchant-attributed balances/transactions/payouts and reports.
/api/v1/payouts*
Creates and reads corporate payout instructions to V-REC beneficiaries. Creating a payout does not itself credit funds.
/api/v1/me/*
Authenticated cardholder KYC, card issuance/actions, personal balances/transactions and step-up sensitive-card display.
/api/integrations/vrec/*
Internal V-REC ↔ SAKURA integration for profile/KYC, cards and Tenant Funding status/balance/fund/return/usage. This is not a direct public Merchant API.
v2.5.0: the crypto wallet (crypto_wallet / crypto_wallet_manage) uses the same channel.
Merchant-scoped lessons and progress, external completion evidence, approved Google Calendar sync, dedicated pool history and gasless payout requests. Call through a signed merchant backend, not in-browser HMAC.
Open the 12-endpoint web reference · Integration flow · OpenAPI YAML
The Merchant API is server-to-server only. The Merchant boundary is derived from the credential and never from merchant_id in the request body.
METHOD + "\n" +
PATH + "\n" +
CANONICAL_QUERY + "\n" +
TIMESTAMP + "\n" +
NONCE + "\n" +
SHA256(raw_body)/api/merchant/v1/contextAuthenticated Merchant context and available scopes
/api/merchant/v1/profile-optionsSAKURA-owned country / dial-code catalog
/api/merchant/v1/usersList V-REC users belonging to this Merchant
/api/merchant/v1/usersCreate a user. Idempotency-Key required
/api/merchant/v1/user-linksGenerate a user-consent URL for an existing SAKURA user
/api/merchant/v1/user-links/{id}Check existing-user consent-link status
/api/merchant/v1/users/{id}User detail
/api/merchant/v1/users/{id}/statusACTIVE / SUSPENDED
/api/merchant/v1/users/{id}/kycSynchronize and read current SAKURA KYC state
/api/merchant/v1/users/{id}/kyc/startRequire the user to continue in V-REC. No eKYC URL is returned to the Merchant
/api/merchant/v1/crypto-salesv2.6.0 Crypto sales and royalties (crypto_sales.read)
/api/merchant/v1/users/{id}/walletv2.5.0 read-only wallet address and balances (wallets.read)
/api/merchant/v1/users/{id}/cardsMasked cards only; never PAN/CVV
/api/merchant/v1/users/{id}/cardsIssue VIRTUAL cards (operator-granted cards.issue, Idempotency-Key required)
/api/merchant/v1/users/{id}/cards/issuance/{key}Inspect issuance result; uncertain outcomes require operator reconciliation, not reissuance
/api/merchant/v1/users/{id}/cards/{cardId}/transactionsMatchMove issuer card transactions (transactions.read)
/api/merchant/v1/users/{id}/cards/{cardId}/statusExplicit cards.manage grant allows FREEZE/SUSPEND (issuer FROZEN) or UNFREEZE. Permanent CLOSE is not supported.
/api/merchant/v1/users/{id}/cards/{cardId}/sensitive-linkIssue hosted one-time cardholder password form URL; Merchant never receives PAN/CVV (operator-granted cards.sensitive.link)
/api/merchant/v1/users/{id}/matchmove-balanceIssuer MatchMove live balance via SAKURA, separate from ledger; fails 503 when unavailable
/api/merchant/v1/users/{id}/cards/physical/linkLink a pre-issued physical card by Proxy / Association ID
/api/merchant/v1/users/balancesbalances.read · Bulk Merchant-attributed balances of your users (up to 200 per call)
/api/merchant/v1/users/{id}/balanceMerchant-attributed balance
/api/merchant/v1/users/{id}/transactionsMerchant-attributed transactions
/api/merchant/v1/payoutsRead payouts associated with this Merchant
/api/merchant/v1/reportMerchant summary report
POST /api/merchant/v1/users automatically sends the applicable V-REC password email and SAKURA password email by default. Set notifications.send_vrec_activation_email and notifications.send_sakura_password_setup_email as JSON booleans to control the two emails independently.
"notifications": {
"send_vrec_activation_email": false,
"send_sakura_password_setup_email": true
}The V-REC email is applicable only to a newly created local login. The SAKURA email is applicable only when SAKURA returns a one-time setup URL. The SAKURA setup URL is not exposed through the Merchant API. Check user.notifications in the response for sent / disabled / not_applicable / failed.
The Corporate / Partner Payout API moves MatchMove USD from the Merchant bound to an approved Partner to a V-REC beneficiary's MatchMove USD wallet. A Tenant that directly allocates funds uses the separate Merchant Tenant Funding API. Payouts created through this API are never funded by Tenant Funding.
Funding requires verified settlement Reference-only LEGACY_REFERENCE payouts cannot be created; new payouts require MERCHANT_BALANCE. A payout becomes CREDITED only when SAKURA returns COMPLETED for the same payout ID, beneficiary, asset and amount with a MatchMove transaction ID and SAKURA transfer UUID. Transfer evidence is stored before the ledger lot is created; if only the lot creation is deferred the payout stays FUNDED and /reconcile retries it. On timeouts, never resubmit; reconcile the existing payout.
/api/v1/payoutsCreate a payout instruction (no money moves). Idempotency-Key required. PENDING_FUNDS when SAKURA KYC is approved, otherwise AWAITING_KYC. A replay with the same key returns the original payout (201) only if every field is identical.
/api/v1/payouts/{id}/fundAsk SAKURA to transfer MATCHMOVEUSD→MATCHMOVEUSD. Body is a signed {}. HTTP 200 is not success by itself; read status and merchant_transfer_status. Repeating it for the same payout is safe and never sends twice. May take up to 150 seconds.
/api/v1/payouts/{id}/reconcileRead-only reconciliation (never resends). Body is {}. Use for uncertain, in-progress or credit-deferred payouts.
/api/v1/payouts/{id}/cancelCancel only when SAKURA confirms no transfer can have happened. Body is {}. The external_reference stays reserved after cancellation.
/api/v1/payouts/{id}/approval-statusRead the Merchant over-limit approval state from SAKURA. Call /fund again for the same payout only when fund_retry_permitted=true.
/api/v1/payoutsList Partner payouts (newest 100, no paging)
/api/v1/payouts/{id}Get payout (stored V-REC state; does not call SAKURA)
/api/v1/beneficiaries/{id}/statusCheck beneficiary status/KYC
/api/v1/webhooks/testVerify Partner API signing (echoes your JSON; does not send a webhook)
POST /api/v1/payouts only records an instruction. Money moves through /fund, and the payout becomes CREDITED once SAKURA transfer evidence is verified. Tenant Funding only funds historical LEGACY_REFERENCE payouts.
The Partner API canonical string differs from the Merchant API (different order, no query). Do not reuse the Merchant API implementation.
X-VREC-Key: vrec_... # Partner key ID
X-VREC-Timestamp: 1792540800 # Unix seconds, within ±300 s
X-VREC-Nonce: 7d1c... # unique, 1-128 chars, never reused
X-VREC-Signature: hex HMAC-SHA256
body_hash = hex(SHA256(raw_body)) # GET: SHA256("") = e3b0c442...b855
message = TIMESTAMP + "\n" + NONCE + "\n" + METHOD + "\n" + PATH + "\n" + body_hash
signature = hex(HMAC-SHA256(message, partner_secret))
# PATH = URL path only, e.g. /api/v1/payouts/po_abc/fund
Every POST requires a JSON object body; send {} when there are no fields (an empty body returns 400 invalid_json). Authentication errors are 401 (partner_not_authorized / stale_timestamp / invalid_nonce / invalid_signature), a reused nonce is 409 replayed_nonce, and a non-allow-listed IP is 403 ip_not_allowed.
Amounts are in USD. Both source_asset and destination_asset are required and must match. Only MATCHMOVEUSD-to-MATCHMOVEUSD can be funded; USD-to-USD and SGP-USD-to-SGP-USD can be created but are rejected by /fund. Cross-asset conversion is prohibited.
POST /api/v1/payouts
Idempotency-Key: corp-20261021-0001
{
"beneficiary_id": "VREC-...",
"merchant_id": "mrc_...", // optional, see OpenAPI
"amount": "100.00", // string, max 2 decimals
"currency": "USD",
"funding_mode": "MERCHANT_BALANCE",
"source_asset": "MATCHMOVEUSD",
"destination_asset": "MATCHMOVEUSD",
"external_reference": "INVOICE-2026-10-001", // required, unique per Partner
"purpose": "corporate_payout" // optional, max 80 chars
}
→ 201 {"id":"po_...","status":"PENDING_FUNDS","merchant_transfer_status":null, ...}
POST /api/v1/payouts/po_.../fund body: {}
→ 200 {"status":"CREDITED","merchant_transfer_status":"COMPLETED","provider_tx_id":"...", ...}
| merchant_transfer_status | What to do |
|---|---|
COMPLETED + CREDITED | Done |
COMPLETED + FUNDED | Transfer confirmed; ledger credit deferred (e.g. KYC). Call /reconcile later |
SUBMITTING | In progress. Check with GET or /reconcile |
RECONCILE_REQUIRED | Outcome uncertain. Use /reconcile only; never create a new payout |
RETRYABLE | Proven not sent. Check merchant_pre_submission_reject_code, fix the cause, then /fund the same payout again or /cancel |
FAILED_CONFIRMED | Operations confirmed non-execution. /cancel, then create a new payout with a new external_reference |
Prerequisites: an approved Partner bound to the Merchant, an APPROVED and ACTIVE/FULL beneficiary, the corporate_payout Connected App scope, and a Merchant-enabled payout policy (per-payout and daily limit, UTC day) in SAKURA Merchant console → “V-REC Corporate Payout”. Without it /fund returns RETRYABLE (corporate_payout_policy_not_enabled).
Over a limit: /fund returns RETRYABLE (corporate_payout_merchant_approval_required) and SAKURA queues an approval request. After the Merchant approves it in SAKURA (valid 24 hours), confirm fund_retry_permitted=true via GET /approval-status, then call /fund for the same payout. If it is not approved you can /cancel.
Full parameters, responses and error codes: Payout OpenAPI →
V-REC does not maintain an independent authoritative Tenant available balance. Use balance/capacity to read SAKURA-authoritative state, then execute either direct allocation or payout-based funding. New money movement is allowed only for an ACTIVE/FULL membership whose source Merchant equals the Tenant Merchant. READONLY may still read masked card metadata, but cannot receive new Tenant funds.
Current funding requires more than the V-REC tenant_funding.read/write HMAC permission: existing SAKURA Connected Apps must be explicitly reauthorized for tenant_funding and checked for exact Merchant/origin/program binding, ENFORCED, api_execute_enabled and reconciliation state. Missing grants or READONLY membership block new allocations.
/api/merchant/v1/tenant-funding/balancetenant_funding.read · SAKURA-authoritative available / reserved / expiry policy
/api/merchant/v1/tenant-funding/diagnosticstenant_funding.read · Read-only verification of schema, binding, SAKURA, membership, source/target Merchant and operation readiness
/api/merchant/v1/tenant-funding/users/{id}/capacitytenant_funding.read · Preflight membership eligibility and allocatable amount (tenant available − allocation fee)
/api/merchant/v1/tenant-funding/allocationstenant_funding.write · Direct Tenant→User allocation. Idempotency-Key required. 409 + REJECTED when not executed (e.g. insufficient balance, or another operation in progress: operation_in_progress / unresolved_request_exists). REJECTED moved no money; fix the cause and retry with a new Idempotency-Key.
/api/merchant/v1/tenant-funding/allocationstenant_funding.read · List allocations updated since a given time (for cron result collection)
/api/merchant/v1/tenant-funding/allocations/{id}tenant_funding.read · Read allocation operation status
/api/merchant/v1/tenant-funding/allocations/{id}/reversetenant_funding.write · Return only unspent principal from that allocation
/api/merchant/v1/tenant-funding/users/{id}/returntenant_funding.write · Return user-held principal originating from this Tenant
Direct allocation
GET /tenant-funding/balance
GET /tenant-funding/users/{id}/capacity
↓ eligible / available
POST /tenant-funding/allocations + Idempotency-Key
↓
V-REC re-checks Membership + SAKURA status
↓
SAKURA /api/integrations/vrec/tenant-funding/fund
↓ 201 COMPLETED / 409 REJECTED (not executed) / 202 UNKNOWN (retry same key)
GET /tenant-funding/allocations?updated_since=… (cron result collection)
V-REC creates provenance lot with expiry snapshot
Payout-based funding (historical LEGACY_REFERENCE payouts only)
existing LEGACY_REFERENCE payout, KYC APPROVED
↓ tenant-funding cron, same SAKURA fund guard
↓ COMPLETED
Payout = CREDITED
# New payouts (MERCHANT_BALANCE) are never funded by Tenant Funding.
Expiry (including a 180-day policy where applicable) is stored on the V-REC lot from the effective SAKURA snapshot returned at allocation execution. Viewing, spending or returning the lot does not restart the expiry period.
SAKURA /api/integrations/vrec/tenant-funding/* remains an internal Connected Apps API. External Merchants must use /api/merchant/v1/tenant-funding/* instead of calling the SAKURA integration endpoints directly.
/api/v1/meAuthenticated user context
/api/v1/me/kycOwn KYC state
/api/v1/me/kyc/formFetch current dynamic SAKURA KYCFORM
/api/v1/me/kyc/submitSubmit KYC and follow next_action
/api/v1/me/cards/VIRTUALIssue a virtual card after KYC approval
/api/v1/me/cards/PHYSICALIssue a physical card after KYC approval
/api/v1/me/cards/physical/linkCardholder step-up to link a pre-issued physical card
/api/v1/me/cards/{id}/sensitiveTemporary PAN/expiry/CVV after current-password step-up; no-store
/api/v1/me/walletv2.5.0 wallet summary, USDT/ETH balances, gasless eligibility
/api/v1/me/walletCreate an unhosted wallet after step-up; seed phrase returned once (no-store)
/api/v1/me/wallet/rotateRotate the wallet after step-up
/api/v1/me/wallet/purchase-quotesv2.6.0 Quote a purchase of SGP-USD / merchant points paid in crypto (sale contract)
/api/v1/me/wallet/purchases/{contract}/confirmAccept terms and pay (company 1% + merchant royalty)
/api/v1/me/wallet/gasless-transferUSDT gasless transfer; Idempotency-Key required, gas paid by SAKURA
/api/v1/me/balanceUser V-REC balance
/api/v1/me/transactionsUser transactions
/api/v1/me/payoutsPayouts received by the user
profile-options → POST /merchant/v1/users
kyc/start → user login → /me/kyc/form → submit → webhook
beneficiary/status → POST /api/v1/payouts (MERCHANT_BALANCE)
POST /api/v1/payouts/{id}/fund → (approval-status) → reconcile
Tenant allocations use a separate API: /api/merchant/v1/tenant-funding/allocations
KYC APPROVED → /me/cards/VIRTUAL|PHYSICAL
GET payout / Merchant balance / user balance / webhooks
user.kyc.updatedSigned Merchant notification carrying the latest KYC state re-read from SAKURA
payout.created / payout.creditedPartner payout notifications (these two only; cancellation and reconciliation states are not notified). There is no event ID: deduplicate on X-VREC-Event + payout.id and confirm state with GET. Signature contract →
Keep webhook secrets server-side and verify signatures against the raw request body.
There is no direct Merchant fund endpoint. User payout instructions are created through the Partner Payout API. Operator-granted Merchant credentials may issue VIRTUAL cards, but do not receive PAN/CVV. Cardholders must enter their V-REC password into a short-lived one-time hosted V-REC page to view sensitive details. An explicitly granted cards.manage Merchant credential can freeze/unfreeze cards, but cannot access PIN or PAN/CVV.