Skip to main content
Crewship exposes agent webhooks and pipeline-webhook triggers. Agent webhooks target one agent; pipeline webhooks target a saved routine. Both are asynchronous and return 202 after authentication and admission checks.
This endpoint uses webhook-secret authentication only — not session or CLI token auth. Provide exactly one of X-Signature (preferred) or X-Webhook-Secret (deprecated).

Trigger Agent via Webhook

Triggers an agent run from an external system. The webhook validates the request against the agent’s per-agent webhook secret, then starts the agent asynchronously.

Authentication

The endpoint accepts two header-based schemes. Provide one of them; if both are absent the request is rejected with 401. X-Signature (preferred). A hex-encoded HMAC-SHA256 of the raw request body, keyed by the agent’s per-agent webhook secret (no sha256= prefix):
This binds the signature to the exact payload, so a leaked header from one request can’t be replayed against a different body. Replay protection (optional, recommended). Add an X-Timestamp header (unix seconds). When present, the signature must cover "{timestamp}.{body}" and the timestamp must be within 5 minutes of the server clock — a captured signed request replayed after that window is rejected with 400, and the timestamp itself can’t be swapped because it is part of the signed material:
Requests without X-Timestamp keep the body-only scheme above (backward compatible). When a signature is present it is also used as the dedup identity (instead of any client-supplied Idempotency-Key), so a replay can’t force a second run by supplying a fresh key. Enforcing timestamps per agent. The timestamped scheme is optional by default so un-migrated senders don’t break — but a body-only signature stays replayable indefinitely (bounded only by the dedup window). Once an agent’s sender emits X-Timestamp, flip the agent to require it:
(API: PATCH /api/v1/agents/{id} with {"webhook_require_timestamp": true}; the current value is echoed on GET /api/v1/agents/{id} and in crewship agent get.) With it on, a body-only HMAC and the deprecated plaintext X-Webhook-Secret are both rejected with 400 pointing at the {timestamp}.{body} scheme — closing the replay window entirely for that agent. X-Webhook-Secret (deprecated). The per-agent secret sent in plaintext:
This path still works during the deprecation window but is going away. Requests authenticated this way receive Deprecation and Sunset: Thu, 31 Dec 2026 23:59:59 GMT response headers.
X-Webhook-Secret is deprecated (sunset 2026-12-31). Migrate to X-Signature before the sunset date.
Both schemes validate using constant-time comparison. This endpoint does not use session or CLI token authentication.

Path Parameters

Request Headers

Request Body

The payload is passed to the agent as context. The structure is flexible — include whatever data is relevant to the agent’s task.
The agent receives a formatted message:

Response

The webhook returns immediately. Agent execution happens asynchronously. 202 Accepted on success — the body is {"status": "accepted"}. The status reflects the fire-and-forget contract: the agent run is enqueued asynchronously, and 202 (not 200) signals “we received it, work has not finished”. 401 Unauthorized if neither X-Signature nor X-Webhook-Secret is provided, or the supplied signature/secret is invalid. 400 Bad Request if X-Timestamp is present but unparseable or outside the 5-minute tolerance (a stale or replayed signed request).

What Happens Behind the Scenes

  1. Auth validation — the agent’s webhook secret is read crew-scoped from the database (the plaintext secret never crosses an IPC hop); an X-Signature is verified as an HMAC of the body (or of "{timestamp}.{body}" when X-Timestamp is present, which must also be within the freshness window), otherwise a plaintext X-Webhook-Secret is compared (constant-time)
  2. Agent config resolution — the agent’s full configuration (CLI adapter, LLM model, credentials, etc.) is resolved
  3. Chat session creation — a webhook-scoped chat session is created or reused (webhook-{agentId})
  4. Container startup — the crew’s container runtime is ensured running
  5. Run record creation — a run record with trigger type WEBHOOK is created
  6. Ingress trust fence — the payload (event, source, data) is external, attacker-controlled input, so it is wrapped in a nonce-delimited <untrusted …> block and injection-scanned before it becomes the agent’s user message. The agent’s system prompt instructs it to treat fenced blocks as pure data, never as instructions. See Ingress trust fence.
  7. Agent execution — the agent is started asynchronously with a 10-minute timeout
  8. Log streaming — agent output is streamed to the log collector and broadcast via WebSocket on workspace:{workspaceId}
  9. Run completion — the run record is updated with status (COMPLETED or FAILED), exit code, duration, and error message

Prerequisites

The webhook endpoint is only registered when all of the following are configured:
  • Orchestrator is available
  • Container provider (Keeper) is available
  • Log writer is configured
  • Internal token is set
If any prerequisite is missing the route is never registered, so the endpoint returns 404.

Use Cases


Monitoring Webhook Runs

After triggering, use these endpoints to monitor execution:

Getting the Webhook Secret

The webhook signing secret follows show-once semantics — the same convention as CLI tokens and notification-channel secrets. No API, CLI, or UI surface ever returns a stored secret back. To obtain one, rotate:
or via the API:
or from the dashboard: Agent → Settings → Advanced → Webhook signing secret → Rotate. The UI confirms first (the previous secret stops validating the instant the new one is minted), then shows the value once with a copy button — it is never re-displayed on a reload. The response contains the freshly minted webhook_secret exactly once — store it in the external system (GitHub/Grafana/… webhook config) immediately. Deliveries signed with the previous secret are rejected as soon as the rotation lands. Rotation requires agent-edit rights (OWNER/ADMIN, or MANAGER for agents they created). GET /api/v1/agents/{agentId} exposes only a webhook_secret_set boolean so clients can tell whether a secret is configured.
The former internal endpoint GET /api/v1/internal/agents/{agentId}/webhook-secret was removed — the trigger endpoint validates signatures against the database directly, and the plaintext secret never crosses an IPC hop.

Pipeline webhooks

Pipeline-webhook administration is workspace-authenticated. Dispatch is public: the high-entropy token in the URL plus its HMAC signature are the credentials. Create accepts either target_pipeline_slug or target_pipeline_id:
name defaults to the target slug. If signing_secret is omitted, the server generates one. The 201 response includes signing_secret exactly once; list responses include signing_secret_set, not the secret. The response also contains token, target identifiers/version, inputs_template, enabled, rate-limit and last-fire telemetry. A zero or negative configured rate uses the server floor of 600 fires/minute. Creation requires encrypted credential storage; misconfiguration is 500. Invalid target/body is 400, and insufficient role is 403.

Pipeline dispatch

The signature is required. With X-Crewship-Timestamp: <unix-seconds>, sign <timestamp>.<raw-body>; the timestamp must be fresh. The body may be any JSON (or raw bytes): the routine receives request-derived event, raw, and headers inputs. inputs_template may add keys but cannot override those three fields. Idempotency-Key (or X-Crewship-Event-ID) can select the deduplication identity; identical signed deliveries also deduplicate. Success returns:
A duplicate returns 202 with status: "DEDUPED", the original run_id, and deduped: true. The run may later be COMPLETED, FAILED, CANCELLED, or WAITING; poll /api/v1/workspaces/{workspaceId}/pipeline-runs/{runId}. Dispatch does not accept session/JWT authentication, and it never falls back to an unsigned request.