Skip to main content

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 via salesmanId/salesmanIdentifier, or a full salesman object for auto-create. See sale-via-api.md.

Sandbox outcome rules

  • Every sale is created with status IN_PROGRESS.
  • Recommended: include NO_CANCEL in folioExternal to 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 becomes REJECTED after ~5 seconds.
    • Else if it contains NO_CANCEL: status remains IN_PROGRESS (no auto transition).
    • Else: status becomes APPROVED after ~5 seconds.
  • Without NO_CANCEL you have ~5 seconds to resolve before the auto transition claims the sale; after that, resolve-transaction fails with TRANSACTION-NOT-IN-PROGRESS.

Mock the client response

  • Endpoint: POST /commerce/resolve-transaction (sandbox-only; fails with SANDBOX-ONLY-ENDPOINT in production)
  • Input: folio or folioExternal, plus status: APPROVED, REJECTED, EXPIRED, CANCELED, or RETURNED.
  • 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 with NO_CANCEL in folioExternal so the sale is still IN_PROGRESS when you resolve. See sale-via-api.md for 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 >= 500 is required; otherwise rejected with SALE-CREATION-03.
  • Credit line: total must be <= availableAmount + lineExtensionAvailable of the client, otherwise SALE-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 (APPROVED or REJECTED).
  • 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

CaseInput (key fields)Expected status progression
Approve via resolveCreate with NO_CANCEL, then resolve with APPROVEDIN_PROGRESSAPPROVED
Reject via resolveCreate with NO_CANCEL, then resolve with REJECTEDIN_PROGRESSREJECTED
Expire via resolveCreate with NO_CANCEL, then resolve with EXPIREDIN_PROGRESSEXPIRED
Stays unresolvedCreate with NO_CANCEL, never resolveIN_PROGRESS (stays)
Cancel in progressCreate with NO_CANCEL, call cancelCANCELED
Auto approvefolioExternal without flagsIN_PROGRESS → (≈5s) APPROVED
Auto rejectfolioExternal contains REJECTEDIN_PROGRESS → (≈5s) REJECTED
Below minimumtotal < 500Error SALE-CREATION-03
Exceeds linetotal > available + extensionError SALE-CREATION-04

Web Component / Hosted Checkout

  • Endpoint: POST /sale-link/generate
  • Optional inputs: amount, clientUsername, salesmanIdentifier, storeId, description, externalId, ticket, callbackUri.
  • Response: link, token (checkout token).
  • 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.
  • callbackUri is honored to redirect the enclosing app/site at completion.
  • Link expiry is handled by the platform; use /sale-link/validate to 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). See sale-via-api.md.
  • ticket: Optional POS receipt/reference; free-form string (recommended ≤ 64 chars).
  • One-of semantics: Provide either clientUsername or clientId; either salesmanIdentifier or salesmanId.

Best practices for testing

  1. Start with a normal approval flow: create a sale with NO_CANCEL in folioExternal, resolve it with status: "APPROVED", and verify the status change.
  2. Test rejection by resolving with status: "REJECTED".
  3. Test manual cancellation by creating with NO_CANCEL and calling /commerce/cancel-transaction.
  4. Exercise the automatic transitions (no flag → APPROVED ~5s, REJECTED flag → REJECTED ~5s) if your integration relies on them.
  5. Validate webhook reception and HMAC/Bearer verification.
  6. Exercise preview endpoints to ensure your selection UI behaves as expected.