Skip to main content
Status: Developer preview — the Fabric v1 API described here is contract-stable but not yet serving traffic. Contact us to join the first partner cohort.
This page defines the vocabulary of the fabric: runs, events, approvals, policies, receipts, tenants, keys, and how billing works.

Runs

A run starts when you call POST /v1/execute. It has two shapes:
  • mode: "turn": a synchronous request. You get a Server-Sent Events (SSE) stream back on the same connection, and the run ends when the stream ends.
  • mode: "task": a durable run. The call returns a run id immediately, and the run keeps going in the background. You track it by reading its state, subscribing to its event stream, or registering a webhook.
Both shapes go through the same admission path and the same policy engine. The difference is only how you receive output. Once a run exists, these endpoints operate on it:

Events

Runs and turns emit a typed stream of events. Each event carries a requestId, a strictly increasing sequence number, and a timestamp. Every stream ends in exactly one terminal event. Non-terminal events include:
  • request.accepted: the request was admitted, and whether this is a replay of an earlier request with the same idempotency key.
  • model.started: a model call began.
  • text.delta: a chunk of streamed text.
  • reasoning.status: a status update while the model is working.
  • tool.proposed: the model wants to call a tool.
  • approval.required: a step is paused pending approval (see Approvals below).
  • tool.started, tool.completed, tool.failed: a tool call’s lifecycle.
  • memory.read, memory.write: memory access, scoped to user, organization, or conversation.
  • output.structured: a structured output payload matching a schema you requested.
  • ui.component: a UI component to render.
  • usage: token and call counts so far.
  • warning, retry: non-fatal issues and retry attempts.
Terminal events, exactly one per stream:
  • response.final: finished normally, with a finishReason of stop, length, tool, content_filter, or other.
  • request.cancelled: the caller or the platform cancelled the run.
  • request.failed: the run failed. Carries an RFC 9457 problem object with a machine-readable code, a human title and detail, and a retryable flag.
For mode: "task" runs, GET /v1/runs/:id/events is resumable: reconnect with a Last-Event-ID header and the stream picks up where it left off.

Approvals: digest-bound resume

When a step needs sign-off, the run pauses and emits approval.required with a summary of the action and an action_digest (a fingerprint of that specific action, arguments included). Show the summary to a human, or route it to whatever approver your policy names, then call:
The design spec names action_digest and decision on this call but does not enumerate decision’s values on the wire; approved and denied mirror Praxa’s internal approval-status enum, and the public contract will confirm them at launch. The digest has to match the paused action exactly. A changed argument, an expired approval, a replayed approval, or an approval posted against the wrong run is rejected. This is the same fail-closed pattern the rest of Praxa’s approval surfaces use: what is shown to the approver is exactly what gets checked before anything runs.

Policies

Before the fabric does anything with real consequences (calling a tool, spending money, touching a connector), one policy engine evaluates the step. It looks at:
  • the tool’s capability metadata (read-only, destructive, human-in-the-loop),
  • the kind of effect the action has,
  • any monetary threshold involved,
  • whether the category is sensitive,
  • how the action compares to the tenant’s history,
  • the tenant’s policy pack,
  • and any standing grants already in place.
It returns one of four decisions: auto, peer_review, human_approval, or deny, plus a TTL and who is allowed to approve. Policy packs are versioned, and the version applied to a run is recorded in that run’s receipt, so a decision can be replayed and audited later. The policy field on POST /v1/execute is a constrained view into this same engine: a risk ceiling, a budget cap, a pinned model lane, a tool allowlist, and an approval mode. You are setting knobs on the platform’s own engine, not writing a parallel rules system.

Receipts

Every run produces a receipt: what ran, which policy version applied, who approved what and against which digest, and whether the outcome was verified against your acceptance criteria. The design calls for receipts to chain together, hashed, into an append-only evidence ledger that exports to PDF or a SIEM. That ledger is still on the fabric’s build list; it does not exist yet, even in preview. The receipt itself is meant to be the artifact you hand to an auditor, or to a customer who asks what the agent actually did.

Tenants and keys

Your organization or account is a tenant. A tenant can be owned by a single user or by an organization; organizations are becoming first-class billing subjects in their own right rather than riding on an owner’s personal plan. A tenant holds one or more API keys, each with its own scopes, expiry, last-used timestamp, rate-limit tier, and revocation state. Keys are hashed at rest; Praxa never stores or displays the raw key after you create it. There are three credential families on the same gateway:
  1. Supabase-authenticated sessions: the Praxa mobile app and Praxa Control desktop app authenticate this way.
  2. aura_agent_* deployment keys: the credential family behind today’s live custom-agent API and embeds. These keep working as they do today.
  3. praxa_sk_* platform API keys: the new fabric tenant model described on this page.
All three resolve through one principal resolver to the same downstream authority checks, fail-closed and server-derived. aura_agent_* keys are expected to move onto the tenant model over time, but that migration does not change how they work today.

Billing: bundled vs. BYO

The fabric supports two ways to pay for the models and tools it calls on your behalf. Bundled is the default: you spend Praxa credits, and every run is priced from a versioned price snapshot at a fixed margin floor. BYO plugs in your own provider credentials; Praxa charges a fee on what gets routed through them instead of marking up tokens. Either way, the routing decisions and the receipts they produce look the same, so switching how you fund runs does not change what you can audit.