V-REC current API workflows
Current implementation order from Merchant user provisioning through KYC, Corporate Payout, Tenant Funding, user credit, cards and reconciliation.
Current authorization prerequisites (2026-10-10)
Tenant Funding requires both V-REC HMAC scopes and an explicitly reauthorized SAKURA tenant_funding scope for the exact Merchant/origin/program binding, along with execute permission and reconciliation readiness. Existing connections are not auto-upgraded.
Check schema, SAKURA binding, membership and operation readiness at GET /api/merchant/v1/tenant-funding/diagnostics?user_id=usr_... . READONLY may still view allowed masked card metadata but cannot receive new Tenant funding.
Learning, calendar and token transfer workflow
External logged-in learner → Merchant backend (user-session check)
→ V-REC HMAC Merchant API → SAKURA Connected Apps → Merchant learning
1. GET /api/merchant/v1/learning/users/{id}/progress
2. GET /api/merchant/v1/learning/programs/{id}/sessions
3. User clicks google_calendar_add_url, or
POST /api/merchant/v1/learning/users/{id}/calendar-sync (consented OAuth only)
4. After ends_at: POST /api/merchant/v1/learning/sessions/{id}/complete
5. GET /api/merchant/v1/learning/rewards (check reward status)
Independent merchant-funded token transfer:
1. GET /api/merchant/v1/token-pool
2. POST /api/merchant/v1/token-pool/transfers (request_id, amount, user_id, merchant_code)
3. GET /api/merchant/v1/token-pool/transfers/{request_id}
4. Reconcile submitted / ambiguous operations before considering confirmation.Requires matching HMAC and Connected Apps grants, ACTIVE/FULL membership and merchant binding. Without Google consent use the click-to-add URL. Payout is unavailable without the dedicated funded wallet and approved relayer.
1. Separate API boundaries first
/api/merchant/v1/*
User management, KYC state, masked cards and Merchant-attributed reads
/api/v1/payouts*
Create and read payout instructions
/api/v1/me/*
Cardholder KYC, cards and personal balance
/api/integrations/vrec/*
Internal integration; not called directly by external Merchants
External Merchant eKYC onboarding flow
A Merchant whose API credential holds kyc.preload / kyc.link.issue can preload profile and KYC evidence after recording user consent (the Merchant grants these in Merchant Portal → Merchant API after an explicit acknowledgement). Only the SAKURA short eKYC link is then delivered privately, without initial V-REC/SAKURA password setup emails.
Merchant backend V-REC API SAKURA/MatchMove
1. GET /profile-options -> current allowed country/dial codes
2. POST /users (ekyc_only) -> SAKURA provision -> user_ref
3. GET /users/{id}/kyc/schema -> SAKURA KYCFORM -> field types/options
4. POST /users/{id}/kyc/preload -> SAKURA draft submission -> validated draft
5. GET /users/{id}/kyc/preload-status -> SAKURA state / owner
POST /users/{id}/kyc/preload-reconcile (only authorized correction)
6. POST /users/{id}/kyc/onboarding-link -> SAKURA eKYC short URL
7. Deliver URL to verified user -> User agrees to SAKURA terms -> MatchMove eKYC
8. GET /users/{id}/kyc -> Poll / stage=final_review if SAKURA not approved -> final review result
Explicit scopes: users.write, kyc.preload, kyc.link.issue, kyc.read. Link issue may return 202 while pending or 409 when the draft is unavailable. Submitting eKYC does not mean APPROVED.
2. Provision the user from Merchant backend
GET /api/merchant/v1/context
GET /api/merchant/v1/profile-options
POST /api/merchant/v1/users
Idempotency-Key: merchant-user-123
Optional request controls:
notifications.send_vrec_activation_email = true|false
notifications.send_sakura_password_setup_email = true|false
Default when omitted: both = true
Save:
user.public_id
beneficiary_id
activation_url (new V-REC login only)
notifications.vrec_activation_email
notifications.sakura_password_setup_emailSelect country_code / dial_code from profile-options. SAKURA is the authoritative profile source. The create-user API can independently enable or suppress the V-REC password email and the SAKURA password email. The V-REC email applies only to a new local login; the SAKURA email applies only when SAKURA returns a one-time password_setup_url. The SAKURA setup URL is never returned to the Merchant API.
3. Hand KYC to the authenticated user session
Merchant backend:
POST /api/merchant/v1/users/{id}/kyc/start
↓ V-REC login URL only
User browser:
GET /api/v1/me/kyc/form
POST /api/v1/me/kyc/submit
↓ next_action
SAKURA / MatchMove review
↓
Merchant webhook: user.kyc.updated
GET /api/merchant/v1/users/{id}/kyc # reconciliationThe legacy kyc/start requires cardholder login; the explicitly authorized new kyc/onboarding-link API can return a short eKYC URL.
4. The user-funding entry point is the Payout API
GET /api/v1/beneficiaries/{beneficiary_id}/status
POST /api/v1/payouts
Idempotency-Key: corp-payment-20261021-001
{
"beneficiary_id": "VREC-...",
"amount": "100.00",
"currency": "USD",
"funding_mode": "MERCHANT_BALANCE",
"source_asset": "MATCHMOVEUSD",
"destination_asset": "MATCHMOVEUSD",
"external_reference": "invoice-001",
"purpose": "corporate_payout"
}
↓ 201 status=PENDING_FUNDS (KYC approved) / AWAITING_KYC
POST /api/v1/payouts/{id}/fund body: {}
↓ 200 read status + merchant_transfer_status
COMPLETED + CREDITED → done
RETRYABLE → fix merchant_pre_submission_reject_code, /fund again (same payout) or /cancel
└ corporate_payout_merchant_approval_required
→ Merchant approves in SAKURA → GET /approval-status (fund_retry_permitted=true) → /fund
SUBMITTING / RECONCILE_REQUIRED / COMPLETED+FUNDED
→ POST /api/v1/payouts/{id}/reconcile body: {} (never a new payout)funding_mode, source_asset, destination_asset and external_reference are required; omitting funding_mode is treated as the disabled LEGACY_REFERENCE mode and rejected. A 201 from POST /payouts moves no money: /fund performs the transfer and the payout becomes CREDITED once SAKURA transfer evidence is verified. See the developers page and the Payout OpenAPI for request signing and every error code. Partner signing →
Building financial reports: Payout / Tenant Funding / Transactions
Tenant Funding and Payout are separate funding sources. A CREDIT is the ledger representation of the source event, not a second deposit.
Direct Tenant Funding → vrec_tenant_allocations (COMPLETED) → ledger_lots + ledger_entries (CREDIT)
Corporate Payout → payouts (CREDITED) → ledger_lots + ledger_entries (CREDIT)
Tenant Return → vrec_tenant_returns (COMPLETED) → ledger_entries (TENANT_RETURN)
Card settlement → V-REC internal card_transactions + MatchMove issuer statement (distinct views)
USDT transfer → SAKURA wallet transfer history (USDT; not a USD tenant allocation)
Crypto sale → payment_asset: USDT or CUSTOM_TOKEN → goods: SGP-USD or merchant points
5. Tenant Funding: preflight → direct allocation / payout → SAKURA confirmation
Merchant direct allocation
GET /api/merchant/v1/tenant-funding/balance
GET /api/merchant/v1/tenant-funding/users/{id}/capacity
↓
Required:
membership.status = ACTIVE
access_mode = FULL
can_receive_tenant_funds = true
source SAKURA Merchant = target Tenant Merchant
SAKURA management_enabled = true
↓
allocatable_amount = tenant available − funding_fee
↓
POST /api/merchant/v1/tenant-funding/allocations
Idempotency-Key: same logical operation
↓
POST SAKURA /api/integrations/vrec/tenant-funding/fund
↓
amount + fee > available, Merchant wallet short,
or another operation in progress (operation_in_progress / unresolved_request_exists)
→ HTTP 409 + status REJECTED (no funds moved; final — retry with a NEW Idempotency-Key)
temporary conflict / network
→ HTTP 202 + status UNKNOWN (retry with the same Idempotency-Key)
↓
COMPLETED for exact principal (HTTP 201)
↓
V-REC creates tenant-origin provenance lot
+ expiry_policy / granted_at / expires_at snapshot
Payout route (historical LEGACY_REFERENCE payouts only)
PENDING_FUNDS → same guard → SAKURA fund → CREDITED
New MERCHANT_BALANCE payouts are never funded by Tenant Funding.
Result collection (cron)
GET /api/merchant/v1/tenant-funding/allocations?updated_since=…&limit=200
→ follow next_cursor while has_more = true
→ keep the last item's updated_at for the next run
(or receive tenant.funding.allocation.updated webhooks)For cron collection, pass the last updated_at you processed as updated_since and follow next_cursor until has_more is false. An allocation whose result changes gets a newer updated_at and may be returned again; de-duplicate by id. COMPLETED / REJECTED / FAILED / MISMATCH are final states.
A READONLY membership may still read masked card metadata, but new Tenant allocation is rejected with 403. SAKURA independently re-checks source Merchant versus Tenant Merchant, so read visibility never escalates into MatchMove money-movement authority.
A 180-day limit or other effective expiry policy is snapshotted from SAKURA onto the lot at execution and is not restarted by V-REC.
6. Conditions for V-REC CREDIT
Corporate Payout (MERCHANT_BALANCE, MATCHMOVEUSD → MATCHMOVEUSD)
SAKURA status = COMPLETED
AND same payout_ref, beneficiary (user_ref), asset, currency and amount
AND MatchMove provider_tx_id AND SAKURA transfer_uuid present and not reused
↓ evidence stored: underlying_fund_confirmed = 1, status = FUNDED
AND beneficiary KYC = APPROVED AND membership can_spend
↓
Create ledger lot (source_type = CORPORATE_PAYOUT)
↓
Payout status = CREDITED (otherwise stays FUNDED; /reconcile retries the lot only)
Tenant-funded payout (historical LEGACY_REFERENCE only)
SAKURA tenant fund request COMPLETED → funding_reference "sakura:*" → CREDITEDA Tenant Funding Merchant cannot be credited through the legacy manual fund-confirm path. Only funds completed through SAKURA are eligible for user credit.
7. Card operations use the cardholder session
KYC APPROVED
↓
POST /api/v1/me/cards/VIRTUAL
or POST /api/v1/me/cards/PHYSICAL
↓
SAKURA / MatchMove issue
↓
V-REC automatically stores card linkage
↓
GET /api/v1/me/cardsMerchant API can only read masked cards and link a pre-issued physical card by proxy. PAN/CVV is available only through /api/v1/me/cards/{id}/sensitive after cardholder current-password step-up.
Cardholder-only operations (V-REC session)
POST /api/v1/me/cards/{id}/sensitive
_csrf + current_password → PAN / expiry / CVV (no-store)
POST /api/v1/me/cards/{id}/pin
_csrf + current_password + pin + pin_confirmation → {"success":true}
GET /api/v1/me/cards/{id}/issuer-transactions?from=YYYY-MM-DD&to=YYYY-MM-DD&page=1
→ issuer card transactions (limit=20)PIN requires an active physical card and card_sensitive scope. Issuer history requires cards scope and differs from V-REC SGPUSD ledger/approval history. These APIs are not callable with Merchant HMAC credentials.
8. Reconcile balances and transactions by view
/api/merchant/v1/users/balancesBulk Merchant-attributed balances of your users (up to 200 per call, continue with next_cursor)
/api/merchant/v1/users/{id}/balanceMerchant-attributed balance
/api/merchant/v1/users/{id}/transactionsMerchant-attributed transactions
/api/merchant/v1/payoutsMerchant-associated payouts
/api/v1/me/balanceCardholder V-REC balance
/api/v1/me/payoutsPayouts received by cardholder
Merchant-attributed balance and cardholder balance are not the same semantic view. Use the correct source for each UI or reconciliation purpose.
SAKURA SGPUSD gross balance is distinct from externally spendable value. Held V-REC sale lots are not eligible for card loading, bank/agent withdrawals or V-Pay wallet checkout until AML approval and manual prefund confirmation. Ordinary P2P transfers inherit hold status. V-REC GET /api/v1/me/balance is not a MatchMove card-fundable balance endpoint.
9. Use webhooks for events and GET for reconciliation
SAKURA / provider change
↓
V-REC re-reads authoritative state
↓
Signed Merchant / Partner webhook
↓
Receiver verifies raw-body HMAC
↓
Idempotent processing by event/delivery id
↓
GET status endpoint when reconciliation is needed10. Fail closed and retry rules
Do not move funds when SAKURA status is unavailable, disconnected, tenant-inactive or execute permission is off.
Reuse the same Idempotency-Key when retrying the same logical user-create, physical-link, payout, Tenant allocation or reverse/return operation. Retrying with a new key may create a second operation.
Verify raw-body signature and deduplicate by delivery id / payload id.
11. Attach an existing SAKURA user with consent
Merchant backend
POST /api/merchant/v1/user-links
Idempotency-Key: <same logical request key>
↓
authorization_url
↓
User opens SAKURA page
login → review V-REC Merchant → approve / deny
↓
SAKURA callback → V-REC
state + one-time code + remote link_request_id validation
↓
V-REC exchanges code for stable SAKURA user UUID
↓
Global User reuse/create + Tenant membership
↓
GET /api/merchant/v1/user-links/{id}
PENDING / COMPLETED / DENIED / EXPIRED
linked_user_id
membership.access_mode = FULL | READONLYThe Merchant cannot force-select an existing identity by email or SAKURA user id. Same source/target Merchant may become FULL; cross-merchant links become READONLY. READONLY may view masked card/reference balance data, but new Tenant allocation, payout, spend and other money movement are denied.