Sandbox Guide (v1.0)
This guide explains how the sandbox environment behaves and how to test your integration reliably without touching production.
Overview
- Authentication: Same OAuth 2.0 flows as production (see
auth.md). Use sandbox-issued credentials. - Base URLs: Use your sandbox API base. Endpoints are the same as production unless noted.
- Determinism: Sandbox uses simple, deterministic rules so you can simulate specific outcomes.
Transactions (Commerce API)
Create a Sale
- Endpoint:
POST /commerce/generate-sale - Required fields:
total,storeId,folioExternal, and exactly one of (clientId,clientUsername); exactly one salesman source — either lookup viasalesmanId/salesmanIdentifier, or a fullsalesmanobject for auto-create. Seesale-via-api.md.
Sandbox outcome rules
- Every sale is created with status
IN_PROGRESS. - Recommended: include
NO_CANCELinfolioExternalto disable the automatic transition, then drive the outcome explicitly with/commerce/resolve-transaction(see below) or/commerce/cancel-transaction. - Alternative — automatic transitions via
folioExternal:- If it contains
REJECTED(case-insensitive): status becomesREJECTEDafter ~5 seconds. - Else if it contains
NO_CANCEL: status remainsIN_PROGRESS(no auto transition). - Else: status becomes
APPROVEDafter ~5 seconds.
- If it contains
- Without
NO_CANCELyou have ~5 seconds to resolve before the auto transition claims the sale; after that,resolve-transactionfails withTRANSACTION-NOT-IN-PROGRESS.
Mock the client response
- Endpoint:
POST /commerce/resolve-transaction(sandbox-only; fails withSANDBOX-ONLY-ENDPOINTin production) - Input:
folioorfolioExternal, plusstatus:APPROVED,REJECTED,EXPIRED,CANCELED, orRETURNED. - Mocks the end client's response to the sale — the client can approve it (
APPROVED) or reject it (REJECTED) in their app, and this endpoint lets you test both branches, plus expiry. Pair it withNO_CANCELinfolioExternalso the sale is stillIN_PROGRESSwhen you resolve. Seesale-via-api.mdfor the full contract.
Cancellation
- Endpoint:
POST /commerce/cancel-transaction - Precondition: Transaction must be
IN_PROGRESS. - Result: status changes to
CANCELED.
Status lookup
- Endpoint:
POST /commerce/transaction-status - Input:
folio - Returns: status and transaction context (storeId, salesmanId, total, clientId, timestamps, comments).
Validation rules (sandbox)
- Minimum amount:
total >= 500is required; otherwise rejected withSALE-CREATION-03. - Credit line:
totalmust be<=availableAmount + lineExtensionAvailableof the client, otherwiseSALE-CREATION-04. - Store/Salesman/Client existence: Must exist and belong to the same company; otherwise the corresponding error code (
SALE-CREATION-01/02/05).
Webhooks in sandbox
- On create: A "transaction created" event is sent with status
IN_PROGRESS. - On resolve: A status-change event is sent with the status you chose in
/commerce/resolve-transaction. - On auto transition (~5s): A status-change event is sent with the final status (
APPROVEDorREJECTED). - On manual cancel: A cancellation event is sent with status
CANCELED. - Delivery: POST requests only; retries with exponential backoff on failures. Implement HMAC or Bearer verification (see
webhooks.md).
Transaction test matrix
| Case | Input (key fields) | Expected status progression |
|---|---|---|
| Approve via resolve | Create with NO_CANCEL, then resolve with APPROVED | IN_PROGRESS → APPROVED |
| Reject via resolve | Create with NO_CANCEL, then resolve with REJECTED | IN_PROGRESS → REJECTED |
| Expire via resolve | Create with NO_CANCEL, then resolve with EXPIRED | IN_PROGRESS → EXPIRED |
| Stays unresolved | Create with NO_CANCEL, never resolve | IN_PROGRESS (stays) |
| Cancel in progress | Create with NO_CANCEL, call cancel | CANCELED |
| Auto approve | folioExternal without flags | IN_PROGRESS → (≈5s) APPROVED |
| Auto reject | folioExternal contains REJECTED | IN_PROGRESS → (≈5s) REJECTED |
| Below minimum | total < 500 | Error SALE-CREATION-03 |
| Exceeds line | total > available + extension | Error SALE-CREATION-04 |
Web Component / Hosted Checkout
Generate link
- Endpoint:
POST /sale-link/generate - Optional inputs:
amount,clientUsername,salesmanIdentifier,storeId,description,externalId,ticket,callbackUri. - Response:
link,token(checkout token).
Validate link
- Endpoint:
GET /sale-link/validate - Uses the checkout token to return the current state (
transactionId,status,client, amounts, store/salesman IDs).
Sandbox notes
- If you do not provide
amount, the embedded UI prompts the value. callbackUriis honored to redirect the enclosing app/site at completion.- Link expiry is handled by the platform; use
/sale-link/validateto refresh state if needed.
Parameters and conventions
folioExternal: External identifier for idempotency; in sandbox it also carries lifecycle flags (REJECTED,NO_CANCEL) and return-simulation flags (COMMERCE_SETTLED,WITH_PAYMENTS,NO_RETURN). Seesale-via-api.md.ticket: Optional POS receipt/reference; free-form string (recommended ≤ 64 chars).- One-of semantics: Provide either
clientUsernameorclientId; eithersalesmanIdentifierorsalesmanId.
Best practices for testing
- Start with a normal approval flow: create a sale with
NO_CANCELinfolioExternal, resolve it withstatus: "APPROVED", and verify the status change. - Test rejection by resolving with
status: "REJECTED". - Test manual cancellation by creating with
NO_CANCELand calling/commerce/cancel-transaction. - Exercise the automatic transitions (no flag →
APPROVED~5s,REJECTEDflag →REJECTED~5s) if your integration relies on them. - Validate webhook reception and HMAC/Bearer verification.
- Exercise preview endpoints to ensure your selection UI behaves as expected.