▸ TLDR
CHECK 04 12 MIN · HANDS-ON

API triggers

What you’ll know by the end of this check

  • What an API trigger gives you that a schedule can’t
  • How to call the /fire endpoint from a shell or CI pipeline
  • Why the text field is freeform (and what that means for JSON payloads)

The shortest possible answer

An API trigger gives a routine a dedicated HTTP endpoint. POST to it with a bearer token, and the routine starts running. Use this to wire Claude into anything that can make an authenticated HTTP call — alerting systems, deploy pipelines, internal tools, cron jobs on your server.

API triggers are configured in the web UI only. Each routine gets its own scoped token.

The shape of a request

curl -X POST https://api.anthropic.com/v1/claude_code/routines/trig_01ABCDEF.../fire \
  -H "Authorization: Bearer sk-ant-oat01-xxxxx" \
  -H "anthropic-beta: experimental-cc-routine-2026-04-01" \
  -H "anthropic-version: 2023-06-01" \
  -H "Content-Type: application/json" \
  -d '{"text": "Sentry alert SEN-4521 fired in prod. Stack trace attached."}'

Successful response:

{
  "type": "routine_fire",
  "claude_code_session_id": "session_01HJKLMN...",
  "claude_code_session_url": "https://claude.ai/code/session_01HJKLMN..."
}

Open the session URL to watch the run live, review changes, or continue the conversation manually.

The text field is freeform

The request body accepts one optional field: text. Whatever you put there is passed to the routine alongside its saved prompt as context.

Important: the value is freeform, not parsed. If you send JSON or another structured payload, the routine receives it as a literal string. So if you want structured data, dump it to a string first and teach your routine’s prompt to parse it:

{"text": "{\"alert_id\":\"SEN-4521\",\"severity\":\"critical\",\"service\":\"checkout\"}"}

Then the routine prompt knows “the text field will be JSON — parse it first.”

What API triggers unlock

  • Alert triage — monitoring system POSTs the alert body when error rate crosses threshold. Routine reads the stack trace, correlates with recent commits, opens a draft PR with a proposed fix.
  • Deploy verification — CD pipeline POSTs after each production deploy. Routine runs smoke checks, scans error logs, posts go/no-go to the release channel.
  • On-demand workflows — internal tool button calls the routine. “Generate this week’s release notes from the last 20 PRs.”
  • Human-triggered automation — Slack command, Linear webhook, whatever can POST. Routine does the thing.

Pattern: event-driven Claude. When the routine shouldn’t run on a schedule because the trigger is an outside event, API trigger.

Token hygiene

  • Each routine has its own token, scoped only to firing that routine.
  • Rotate with Regenerate, invalidate with Revoke — both in the routine’s edit modal.
  • The CLI cannot create or revoke tokens. Web UI only.
  • Treat the token like any production credential: never commit it, store it in your secrets manager, rotate on compromise.

Research preview header

The /fire endpoint ships under the experimental-cc-routine-2026-04-01 beta header. Pin your version. Breaking changes ship behind new dated beta headers with the two most recent versions continuing to work as a migration window. If you’re building production integrations, watch for changelog announcements.

Things to try right now (15 minutes)

  1. Add an API trigger to your test routine from check 02. Copy the endpoint URL and token into a safe place.
  2. From your terminal, run the curl command above against your own endpoint with a trivial text value.
  3. Open the returned session URL. Confirm the routine fired and your text showed up in Claude’s context.
  4. (Optional) Wire it to one real event — a Slack slash command, a monitoring webhook, a CI post-deploy step.

The canonical version

Full official docs: code.claude.com/docs/en/routines. API reference: platform.claude.com/docs/en/api/claude-code/routines-fire.

Ready to verify this check?

You’ve fired a routine via curl. You know the beta-header rule. You understand why text is a string, not JSON. Mark it cleared.