Get Started

Webhooks

Subscribe to real-time agent lifecycle events. Theazo delivers signed HTTP POST requests to your endpoint whenever an agent, session, workflow, or primitive changes state.

Creating a webhook

Register a URL and the set of events you want to receive. The secret field is optional — supply your own or Theazo generates one. Store it securely; you need it to verify signatures.

webhooks.ts
import { Theazo } from class="cb-str">'theazo'

const theazo = new Theazo({ apiKey: class="cb-str">'th_live_...' })

const webhook = await theazo.webhooks.create({
  url: class="cb-str">'https://yourapp.com/webhooks/theazo'.com/webhooks/theazo',
  events: [
    class="cb-str">'agent.completed',
    class="cb-str">'agent.failed',
    class="cb-str">'approval.requested',
    class="cb-str">'fleet.completed',
  ],
  secret: process.env.WEBHOOK_SECRET, class="cb-cmt">// optional — generated if omitted
})

console.log(webhook.id)      class="cb-cmt">// 'wh_abc123'
console.log(webhook.secret)  class="cb-cmt">// shown once — store immediately
The secret is returned in full only on creation. Subsequent calls to theazo.webhooks.list() return the first 8 characters only. If you lose it, delete the webhook and create a new one.

Managing webhooks

theazo.webhooks.create(opts)Promise<Webhook>Register a new endpoint. Returns the full secret once.
theazo.webhooks.list()Promise<Webhook[]>List all registered webhooks. Secrets are masked to first 8 chars.
theazo.webhooks.test(id)Promise<void>Send a test agent.completed payload to the endpoint. Useful for verifying connectivity.
theazo.webhooks.delete(id)Promise<void>Remove the webhook. No further events will be delivered.
webhooks.ts
// List all webhooks
const webhooks = await theazo.webhooks.list()
// [{ id: 'wh_abc123', url: '...', events: [...], secret: 'a1b2c3d4...' }]

// Send a test delivery
await theazo.webhooks.test(class="cb-str">'wh_abc123')

// Delete a webhook
await theazo.webhooks.delete(class="cb-str">'wh_abc123')

Event reference

Subscribe to any combination of events. You can register multiple webhooks with different event subsets and different endpoints.

Agent events

agent.started

An agent has been provisioned and its compute environment is ready. Fired before the first model call.

agent.completed

The agent finished successfully. Payload includes output text, artifact paths, and a structured cost object.

agent.failed

The agent terminated with an error. Payload includes the error code and message.

agent.paused

The agent was paused — either manually via agent.pause() or because a cost/time limit was breached.

Session events

session.limit_reached

A session hit a configured limit (maxCost, maxAgents, or maxComputeMinutes). All running agents in the session are paused.

Workflow events

workflow.started

A workflow run was initiated. Payload includes the workflowId, runId, and total step count.

workflow.step_completed

A single DAG step finished. Payload includes the step name, output, and cost for that step.

workflow.completed

All steps completed successfully. Payload includes the final output and aggregate cost across all steps.

workflow.failed

A step failed and retries were exhausted. Payload includes which step failed and the error.

Fleet events

fleet.started

A fleet job began dispatching agents. Payload includes total item count and concurrency limit.

fleet.item_completed

A single fleet item finished. Payload includes itemIndex, output, and per-item cost.

fleet.completed

All items processed. Payload includes completed count, failed count, and total cost.

fleet.cost_limited

The fleet hit its costCap. Remaining items are cancelled. Payload includes items processed so far.

Approval events

approval.requested

An agent reached a checkpoint requiring human sign-off. Payload includes the action name and parameters preview.

approval.approved

A reviewer approved the action. The agent resumes automatically.

approval.denied

A reviewer denied the action. The agent receives a denial reason and may try an alternative path.

approval.expired

No decision was made within the configured TTL. The agent is paused awaiting manual intervention.

Schedule events

schedule.fired

A cron schedule triggered and dispatched its configured agent.

trigger.fired

A webhook trigger received an inbound request and dispatched its configured agent.

Knowledge events

knowledge.sync_completed

A knowledge source finished ingesting and embedding documents. Payload includes chunk count and storage used.

knowledge.sync_failed

Ingestion failed for a knowledge source. Payload includes the source ID and error details.

Example payload

All events share the same envelope shape. The data field is event-specific. Cost values are always structured objects with integer cent amounts — never strings.

payload.json
// POST https://yourapp.com/webhooks/theazo
// Content-Type: application/json
// X-Theazo-Signature: sha256=a1b2c3...
// X-Theazo-Delivery: del_xyz789

{
  class="cb-str">"id": class="cb-str">"evt_01HX3K2...",
  class="cb-str">"event": class="cb-str">"agent.completed",
  class="cb-str">"createdAt": class="cb-str">"2025-05-06T14:23:01.000Z",
  class="cb-str">"data": {
    class="cb-str">"agentId": class="cb-str">"agt_01HX3K1...",
    class="cb-str">"sessionId": class="cb-str">"ses_01HX3J9...",
    class="cb-str">"userId": class="cb-str">"user_123",
    class="cb-str">"status": class="cb-str">"completed",
    class="cb-str">"output": class="cb-str">"Competitor pricing analysis complete...",
    class="cb-str">"artifacts": [class="cb-str">"/data/report.pdf"],
    class="cb-str">"cost": { class="cb-str">"amount": class="cb-num">47, class="cb-str">"currency": class="cb-str">"usd" },
    class="cb-str">"compute": {
      class="cb-str">"provider": class="cb-str">"e2b",
      class="cb-str">"durationMs": class="cb-num">12400
    },
    class="cb-str">"model": {
      class="cb-str">"provider": class="cb-str">"anthropic",
      class="cb-str">"model": class="cb-str">"claude-3-5-sonnet-20241022",
      class="cb-str">"inputTokens": class="cb-num">1820,
      class="cb-str">"outputTokens": class="cb-num">634
    }
  }
}

Signature verification

Every delivery includes an X-Theazo-Signature header. It is an HMAC-SHA256 of the raw request body, signed with your webhook secret. Always verify before processing.

app/api/webhooks/theazo/route.ts
import { createHmac, timingSafeEqual } from class="cb-str">'crypto'

export function verifyWebhookSignature(
  rawBody: Buffer,
  signatureHeader: string,
  secret: string,
): boolean {
  const expected = class="cb-str">'sha256=' + createHmac(class="cb-str">'sha256', secret)
    .update(rawBody)
    .digest(class="cb-str">'hex')

  const actual = signatureHeader
  if (expected.length !== actual.length) return false

  return timingSafeEqual(
    Buffer.from(expected, class="cb-str">'utf8'),
    Buffer.from(actual,   class="cb-str">'utf8'),
  )
}

// Next.js route handler example
export async function POST(req: Request) {
  const rawBody  = Buffer.from(await req.arrayBuffer())
  const sig      = req.headers.get(class="cb-str">'x-theazo-signature') ?? class="cb-str">''
  const isValid  = verifyWebhookSignature(rawBody, sig, process.env.WEBHOOK_SECRET!)

  if (!isValid) {
    return new Response(class="cb-str">'Unauthorized', { status: class="cb-num">401 })
  }

  const payload = JSON.parse(rawBody.toString())
  class="cb-cmt">// process payload.event ...
  return new Response(class="cb-str">'OK')
}
Use timingSafeEqual to compare signatures. A naive string comparison leaks timing information that an attacker can use to forge signatures.

Delivery and retries

Theazo expects a 2xx response within 10 seconds. If your endpoint times out or returns a non-2xx status, the delivery is retried up to 3 times with exponential backoff (5 s, 30 s, 5 min). After 3 failures the delivery is marked as permanently failed and logged in your dashboard.

Each delivery carries an X-Theazo-Delivery header with a unique ID. Use it to deduplicate retried deliveries in your handler — the same event may arrive more than once.

Was this page helpful?
Ask anything...⌘I