Skip to main content

Documentation Index

Fetch the complete documentation index at: https://enfinitos.mintlify.app/llms.txt

Use this file to discover all available pages before exploring further.

The sandbox HTTP API is a complete subset of the production API, cookie-scoped per visitor. All routes run on Cloudflare Pages’ edge runtime at https://sandbox.api.enfinitos.com and respect a per-IP rate limit of 10 req/10s (burst) + 200 req/hour (sustained).

Auth

Every route after POST /api/sandbox/tenant requires the enf_sandbox_tenant cookie set by that initial call. The cookie value is <tenantId>.<hmac>; tampering breaks the HMAC and the cookie is rejected.

Tenant lifecycle

POST /api/sandbox/tenant

Provision a fresh tenant with the standard seed scenario (3 bases, 4 rights across DOOH, CTV, mobile, messaging). Idempotent — if a valid cookie is present and the tenant exists, returns the existing tenant. Response:
{
  "ok": true,
  "data": {
    "tenantId": "tnt_abc...",
    "orgId": "org_xyz...",
    "createdAt": "2026-05-14T10:00:00.000Z",
    "counts": { "bases": 3, "rights": 4, ... },
    "rights": [{ "id": "rgh_...", "substrate": "DOOH", ... }]
  },
  "rebound": false
}

GET /api/sandbox/tenant

Read-only tenant summary. 404 if no tenant; 410 if tenant evicted (Worker isolate eviction).

POST /api/sandbox/reset

Drop the tenant + clear the cookie. Idempotent.

Rights bounded context

POST /api/sandbox/rights/issue

Body: { basisId, substrate, scope, effectiveFrom, effectiveUntil?, parentRightId? } Issue a new right under an existing basis.

POST /api/sandbox/rights/suspend

Body: { rightId, reason?, action?: "suspend" | "resume" } Suspend a right (default) or resume a suspended one.

POST /api/sandbox/rights/revoke

Body: { rightId, reason? } Terminal — cannot be undone.

Offers

POST /api/sandbox/offers/propose

Body: { rightId, toOrgId, scope, termsRef?, expiresAt? } Propose an offer to share / cede / sublet a right. Default expiry is 7 days from now.

POST /api/sandbox/offers/accept

Body: { offerId } Issues a derived right whose parentRightId points at the original right and contentHash references the accepted offer.

POST /api/sandbox/offers/counter

Body: { offerId, scope, termsRef?, expiresAt? } Counter-offer with revised terms. Original transitions PROPOSED → COUNTERED; a new offer goes the opposite direction with termsRef: "counter_of:<originalOfferId>".

POST /api/sandbox/offers/withdraw

Body: { offerId, action?: "withdraw" | "reject", reason? } Withdraw (proposer) or reject (recipient). Both move PROPOSED to WITHDRAWN/REJECTED respectively.

Challenges

POST /api/sandbox/challenges/open

Body: { rightId, challengerOrgId?, reason } Open a challenge against an active right. Default challengerOrgId is org_thirdparty_sandbox.

POST /api/sandbox/challenges/resolve

Body: { challengeId, upheld?, resolution?, action?: "resolve" | "withdraw" } Resolve as upheld (revokes the right) or overturned (right stays ACTIVE). action: "withdraw" resolves as WITHDRAWN — the challenger backed down.

Delivery + proof

POST /api/sandbox/run-demo

Body: { eventCount?: number (1..100, default 12), seed?: number } Fire N synthetic delivery events with substrate-realistic dwell times. Seals a fresh SignedProofPack containing every receipt plus the projected metering and reconciled settlement.

POST /api/sandbox/constraint-demo

Body: { scenario: "messaging-optout" | "automotive-speed" | "drone-remote-id-missing" } Deliberately configure a delivery that fails the pre-render constraint gate. Returns structured violations; no receipt is signed. Demonstrates real compliance enforcement.

GET /api/sandbox/proof-packs

List sealed packs (summaries only). Newest last.

GET /api/sandbox/proof-packs/[packId]

Full pack JSON plus the sandbox VerificationKey. The verification key is embedded so an offline auditor can verify without a second round-trip.

Provenance + inspector

GET /api/sandbox/provenance?rightId=…

Returns the lineage chain — basis → root right → derived rights → target right.

GET /api/sandbox/inspect

Full read-only tenant snapshot — every basis, right, offer, challenge, event, pack header. Consumed by the Tenant Inspector UI.

Verification keys

GET /api/sandbox/runtime-keys

Public, unauthenticated. Returns the sandbox’s verification-key directory. The auditor SDK consumes this to verify sandbox-issued packs.
{
  "ok": true,
  "contractVersion": "ws30.v1",
  "data": {
    "keys": [{
      "keyId": "<sandbox-key-id>",
      "algorithm": "ed25519",
      "publicKey": "<base64url>",
      "notBefore": "2026-01-01T00:00:00.000Z",
      "notAfter": null,
      "revokedAt": null,
      "purpose": "sandbox_proof_signing"
    }],
    "issuedAt": "<timestamp>",
    "snapshotId": "<sandbox-key-id>"
  }
}

Error responses

Every error returns the same envelope:
{
  "ok": false,
  "error": "STABLE_CODE",
  "message": "Human-readable explanation"
}
Stable codes:
CodeMeaning
NO_TENANTCookie missing — call POST /api/sandbox/tenant first.
TENANT_EVICTEDWorker isolate evicted the tenant. Hit Reset and start fresh.
INVALID_BODYBody wasn’t valid JSON.
MISSING_FIELDSRequired body fields not supplied.
RATE_LIMITEDPer-IP quota hit. Respect the Retry-After header.
HANDLER_ERRORServer-side exception (e.g. state-machine refusal). The message carries the structured cause.
UNKNOWN_SCENARIOconstraint-demo scenario string isn’t recognised.