Skip to main content
Status: Mixed. The publish-and-call flow is available today; the fabric upgrade path is developer preview.
For teams that already run a Praxa custom agent inside their product and want more than one fixed agent’s worth of tools, budget, and approvals — with approvals showing up in your own product instead of Praxa’s dashboard. If you already embed a Praxa custom agent, you’re on the first wedge of the fabric already. This guide covers what you have today, what the fabric adds, and a full worked example — a support-ticket triage agent — showing both.

Today: the custom-agent surface

Status: Available today. aura_agent_* deployment keys and POST /api/custom-agent-run are shipped, working code, not a roadmap description.
  • Publish. Build the agent in the agent builder (instructions, knowledge, bound connectors), publish a version, and Praxa mints a deployment credential for the External API channel — an aura_agent_* key — tied to one deploymentId.
  • Call it. Your backend calls POST /api/custom-agent-run with that key and a stable externalSessionId you generate — a ticket id, a customer id, whatever concept you already key sessions on — so repeated calls land in the same conversation.
  • Approvals. Any step that would send, schedule, change, or purchase through a bound connector doesn’t fire automatically. It produces a pending action instead — the exact provider, action, and arguments, frozen — reviewed inside Praxa’s own agent workspace by someone with review access on that agent.
  • Receipts. Conversations, per-agent operational analytics, and cost/charge/contribution-margin — all inside Praxa’s dashboard.

The fabric upgrade

Status: Developer preview. /v1/execute and the rest of /v1/* are developer preview: the wire contracts are stable and published, but no public endpoint serves them yet. task, context, tools, policy, delivery, mode, run_id, action_digest, decision, and the Idempotency-Key header are the vocabulary the design spec (§3.1) gives; tools as an { allow, deny } filter is independently confirmed against the published wire schema. Anything else shown below (webhook registration fields, the keys inside policy) is a reasonable illustration, not a frozen contract — see api/execute.md.
  • Instead of (or alongside) one fixed agent, you call POST /v1/execute with a task, a tool allowlist, and a policy (risk tier plus budget cap) — under a praxa_sk_ tenant key instead of an aura_agent_* deployment credential. See keys-and-access/api-keys.md for how the two key families differ and coexist — aura_agent_* isn’t being retired.
  • Approvals move into your product. Register a webhook once (POST /v1/webhooks), and a pending action reaches your backend directly as a signed approval.required event instead of sitting in Praxa’s dashboard. You render it in your own UI and post the decision back to POST /v1/runs/:id/approve.
  • The trust rule doesn’t change, only where you see it: an approval only ever matches the exact action it was issued for.

Worked example: support-ticket triage

The problem. TicketFlow’s support agent drafts replies to incoming tickets and, for routine ones, sends them. Nobody wants it sending anything unsupervised — every outbound reply needs a human’s okay — and TicketFlow’s ops lead doesn’t want to leave their own helpdesk to give it. What you build.
  • Today: one custom agent (“Ticket Triage”), instructions for tone and scope, a connector bound for sending replies, published, with a deployment credential.
  • Upgrade: the same logic as an execute-API task — a tool allowlist of read_ticket_history, draft_reply, send_reply; a budget cap; send_reply classified to require approval — plus one webhook endpoint registered in TicketFlow’s own backend.
The calls. Today, TicketFlow’s backend calls this once per ticket, using the ticket id as the external session so replies to the same ticket land in the same conversation:
externalSessionId is TicketFlow’s own identifier (8–200 characters, letters/numbers/_.:-). The agent drafts a reply. Because the deployment’s connector binding can send messages, that step parks as a pending action instead of firing — reviewed today inside Praxa’s own agent workspace, approved or denied as-is, never edited in place. Upgrade — TicketFlow registers a webhook once:
Then calls /v1/execute per ticket instead of /api/custom-agent-run:
The call returns immediately with a run id: { "run_id": "run_01j9tcket48213000000001" }. read_ticket_history and draft_reply run on their own. send_reply still parks — same rule as today — but now the approval.required event lands on TicketFlow’s own webhook, HMAC-signed and retried if their endpoint is briefly down, instead of sitting in Praxa’s dashboard. When their ops lead approves it in TicketFlow’s own queue, TicketFlow’s backend posts the decision back:
Only that exact reply, to that exact ticket, is allowed to send. Nothing else matches the digest — if the draft needs to change, the agent has to draft again. What the user experiences. TicketFlow’s customer sees no difference — a reply arrives once it’s approved, same as before. TicketFlow’s ops lead is the one who feels the upgrade: instead of leaving their helpdesk to approve something in Praxa’s dashboard, the pending reply shows up in the same queue as everything else they triage. What the receipt shows. Today: the conversation record, plus Praxa’s own per-agent cost, charge, and contribution-margin analytics. On the fabric: the run and usage endpoints are designed to carry which tools ran, the policy version that gated send_reply, and the decision and digest that authorized the send, rolled into TicketFlow’s tenant-level usage — see api/runs.md and api/usage.md for exactly what’s confirmed on the wire today versus what’s still firming up. A fuller exportable audit trail is on the roadmap, not shipped.

See also