V-RECReceive. Use. Connect.
IMPLEMENTATION WORKFLOWS

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.

API details / IN & OUT →

1. Separate API boundaries first

Merchant Server API

/api/merchant/v1/*

User management, KYC state, masked cards and Merchant-attributed reads

Corporate / Partner Payout API

/api/v1/payouts*

Create and read payout instructions

User Session API

/api/v1/me/*

Cardholder KYC, cards and personal balance

SAKURA Connected Apps

/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.

API details →

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_email

Select 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   # reconciliation

The 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

Read detailed endpoint and asset representation guide →

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:*" → CREDITED

A 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/cards

Merchant 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

GET/api/merchant/v1/users/balances

Bulk Merchant-attributed balances of your users (up to 200 per call, continue with next_cursor)

GET/api/merchant/v1/users/{id}/balance

Merchant-attributed balance

GET/api/merchant/v1/users/{id}/transactions

Merchant-attributed transactions

GET/api/merchant/v1/payouts

Merchant-associated payouts

GET/api/v1/me/balance

Cardholder V-REC balance

GET/api/v1/me/payouts

Payouts 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.

Complete webhook reference: registration, tenant funding, delivery timing, statuses and MatchMove 3-D Secure →

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 needed

10. Fail closed and retry rules

Tenant Funding

Do not move funds when SAKURA status is unavailable, disconnected, tenant-inactive or execute permission is off.

Idempotency

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.

Webhook

Verify raw-body signature and deduplicate by delivery id / payload id.