Documentation: all sections

Saxeo Agents

Saxeo Agents is an agent host where the agent cannot lie about what it did. You deploy a piece of code once; Saxeo runs it on a schedule or when you trigger it. Every run executes under the agent's own bounded API key, is metered, receipted, action-attested, and chained, and the receipt's content fingerprint equals the deploy-time code_fp, proving the deployed code is exactly what ran.

The agent gets SAXEO_API_KEY (its own bounded key) and SAXEO_API_BASE injected into its environment, so it can call Saxeo inference and sandboxes as itself, within its budget, policy, and circuit breaker. Its spend, its receipts, and its run chain are all attributable to that one key.

Deploy an agent

POST /v1/agents (session-authed) stores the code and schedules it.

curl https://www.saxeonetwork.tech/__api/v1/agents \
-H "Authorization: Bearer $SAXEO_SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
  "name": "price-watcher",
  "language": "python",
  "code": "import os, httpx\nprint(os.environ[\"SAXEO_API_BASE\"])",
  "interval_secs": 3600,
  "spend_limit_usd": 5,
  "spend_window": "day",
  "circuit_breaker_usd": 2
}'
{
  "id": "agt_9b41…",
  "name": "price-watcher",
  "language": "python",
  "interval_secs": 3600,
  "enabled": true,
  "code_fp": "f2a91c04…",
  "api_key_id": "key_5d…",
  "run_chain": "agent:agt_9b41…",
  "note": "Code and env are stored sealed and destroyed on deletion. Scheduled-run output is discarded; receipts are the durable record."
}

code_fp is the fingerprint that ties everything together: every run receipt carries the content fingerprint of the code that ran, and for a hosted agent that fingerprint equals code_fp. Anyone holding a receipt can check that the deployed code, not something swapped in later, produced it.

Trigger a run

POST /v1/agents/{id}/trigger runs the agent now and returns the full sandbox response, including output:

curl -X POST https://www.saxeonetwork.tech/__api/v1/agents/$AGENT_ID/trigger \
-H "Authorization: Bearer $SAXEO_SESSION_TOKEN"
{
  "status": "succeeded",
  "exit_code": 0,
  "stdout": "https://www.saxeonetwork.tech/__api/v1\n",
  "stderr": "",
  "cost_micro_usd": 231,
  "receipt": {
    "receipt": "eyJ2Ijoz…",
    "signature": "0x4f8c…",
    "signer": "0xA1b2…9F"
  }
}

The output comes back exactly once and is never stored. Scheduled runs discard their output entirely (see the §3 amendment below): if you need to see what an agent prints, trigger it manually; if you need durable evidence of what it did, that is what the receipts are for.

Triggers

Besides a schedule and the manual trigger, an agent can be started by an event. Both event triggers queue a run rather than running inline, so the caller is never left holding a connection open for a four-hour job.

Inbound webhook

Deploy with "webhook_trigger": true (or mint one later with POST /v1/agents/{id}/hooks/rotate) and you get a trigger URL:

https://www.saxeonetwork.tech/__api/v1/agents/agt_9f3c…/hooks/8Kd2…

The URL is shown exactly once. Only a sha256 of the token is stored, so it cannot be shown again — rotate to mint a new one, which invalidates the previous URL immediately. Treat it as a credential.

A POST to it queues one run and returns 202 straight away:

curl -X POST "$HOOK_URL" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: order-4471' \
  -d '{"order_id": 4471, "total_usd": 89.00}'
{
  "run_id": "arun_2c81…",
  "agent_id": "agt_9f3c…",
  "status": "queued",
  "deduplicated": false
}

The raw request body reaches the run as the environment variable SAXEO_INPUT, and SAXEO_TRIGGER is set to webhook:

import json, os
payload = json.loads(os.environ.get("SAXEO_INPUT", "{}"))
print(payload["order_id"])

Signing inbound requests

Set a secret (at deploy with hook_secret, or later via POST /v1/agents/{id}/hooks/secret) and every inbound POST must carry an HMAC-SHA256 of the raw body in X-Saxeo-Signature, or it is rejected 401:

X-Saxeo-Signature: sha256=<hex hmac of the raw body>
import hashlib, hmac
sig = hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
headers = {"X-Saxeo-Signature": f"sha256={sig}"}

The comparison is constant-time and the secret is sealed at rest and never returned. With no secret configured, unsigned POSTs are accepted — which is fine when the token is the only credential you are relying on, and not fine when the sender is a third party. Set one.

Mailbox messages

Set trigger_on_message: true and a message landing in the agent's mailbox queues a run with SAXEO_TRIGGER=message. The message body is not passed as input: the agent reads its own mailbox with its injected key, which keeps one code path for reading messages whether the run was triggered by a message or by anything else.

At most one queued message-run exists per agent at a time. A burst of ten messages produces one run that drains the mailbox, not ten runs racing over the same inbox.

The hourly breaker

Every agent has max_runs_per_hour (default 60, max 3600), which bounds event-triggered runs — the schedule bounds itself, and a manual trigger is a human. Past it, the trigger gets 429 and no run is queued. It is the runaway fuse for a webhook that starts firing in a loop, complementing the budget and circuit breaker on the agent's key.

Run history

Every run — scheduled, manual, webhook, or mailbox — is a row you can read:

curl https://www.saxeonetwork.tech/__api/v1/agents/agt_9f3c…/runs \
  -H "authorization: Bearer $SAXEO_SESSION"
{
  "agent_id": "agt_9f3c…",
  "runs": [
    {
      "id": "arun_2c81…",
      "trigger": "webhook",
      "status": "succeeded",
      "input_bytes": 44,
      "input_fp": "9c1f3a4b7d2e5061",
      "input_content_type": "application/json",
      "request_id": "sbx_71a…",
      "cost_micro_usd": 231,
      "created_at": "2026-09-04T09:12:03Z",
      "finished_at": "2026-09-04T09:12:09Z",
      "receipt": { "receipt": "eyJ2Ijoz…", "signature": "0x4f8c…", "signer": "0xA1b2…9F" }
    }
  ]
}

Statuses are queuedrunning → one of succeeded / failed / timeout, plus skipped for a run whose agent was disabled or deleted before it was claimed. The record is metadata only: input_bytes and input_fp describe the trigger payload without containing it, and output was never stored at all.

Endpoints

All session-authed (Authorization: Bearer sess_…) except the trigger URL, which authenticates on its own token.

POSTPath/v1/agentsWhat it doesDeploy an agent: seal the code, mint its bounded key, schedule it.
GETPath/v1/agentsWhat it doesList your agents with schedule, last run, and run count.
POSTPath/v1/agents/{id}/triggerWhat it doesRun now; returns the full sandbox response once.
POSTPath/v1/agents/{id}/gateWhat it doesEnable or disable. Body {"enabled": bool}.
POSTPath/v1/agents/{id}/triggersWhat it doesSet trigger_on_message / max_runs_per_hour.
POSTPath/v1/agents/{id}/hooks/rotateWhat it doesMint or replace the inbound trigger URL (shown once).
POSTPath/v1/agents/{id}/hooks/disableWhat it doesDrop the inbound trigger URL.
POSTPath/v1/agents/{id}/hooks/secretWhat it doesSet or clear the HMAC signing secret.
GETPath/v1/agents/{id}/runsWhat it doesThe last 100 runs: metadata plus each signed receipt.
GETPath/v1/agents/{id}/runs/{run_id}What it doesOne run.
DELETEPath/v1/agents/{id}What it doesRevoke the agent's key and destroy its sealed code.
POSTPath/v1/agents/{id}/hooks/{token}What it doesThe trigger URL. Token-authed; queues a run, returns 202.

The bounds

A hosted agent never spends on your root key. Deploying it mints a dedicated key with exactly the bounds you set, enforced on every call the agent makes:

Disable an agent (gate) and its schedule stops; delete it and its key is revoked and its sealed code destroyed.

The proof story

Three artifacts make an agent's history checkable by someone who does not trust you, or Saxeo:

  1. Receipts. Every run mints a signed, metadata-only receipt, verifiable through the public POST /v1/receipts/verify.
  2. The code fingerprint. Each run receipt's content fingerprint equals the deploy-time code_fp, so a receipt proves which code produced it.
  3. The run chain. Every run chains into the agent's own run chain at agent:{id}: a per-agent hash chain you can list at GET /v1/runs/agent:{id}, mint a signed run proof from, anchor, and export as a compliance audit pack.

Together: this code, under this key, ran these times, cost this much, and nothing was inserted or removed from the record.

The §3 amendment

Saxeo's privacy contract says submitted code is never persisted. Hosted agents are the one deliberate, disclosed exception: a scheduler cannot re-run what it does not hold. Plainly stated:

Nothing else about §3 changes: prompts, completions, and one-off sandbox code remain never-persisted, and no receipt or usage row ever contains content.

Scope and limits

Honest scope: Saxeo Agents runs agents on a schedule, on a manual trigger, on an inbound webhook, and on a mailbox message. It is still not an always-on host. An agent is not a resident process: every trigger starts a bounded run that executes and exits, and max_runs_per_hour is a budget on how often that can happen — not a concurrency dial for a daemon. If you need a long-lived listener, run it yourself and call Saxeo from it.