xeroctl webhooks
Subscribe an HTTPS endpoint to project events, fire a test delivery, and audit the delivery log.
Signing secret is returned exactly once at create. Thirty-two event types across eight families: batch, response, file, conversation, exec, agent, join_key, ox.
Overview
- Delivery:
POSTover HTTPS with a JSON body.2xxwithin 10 s counts as success. - Signature:
HMAC-SHA256(secret, timestamp + "." + body), hex-encoded, sent asX-Webhook-Signature. - Replay defence: subscribers must reject deliveries with
X-Webhook-Timestampolder than five minutes. - Retry policy: exponential backoff up to six attempts, terminal state
exhausted; visible via--deliveries. - Test rate:
--testis capped at 10 invocations per hour per webhook.
The webhooks command uses one positional ID plus one action flag
(--create, --update, --delete,
--test, --deliveries). Action flags are mutually
exclusive; omit them all and the command lists.
Usage Pattern
xeroctl webhooks # List all webhooks
xeroctl webhooks <uuid> # Show webhook details
xeroctl webhooks --create --url <url> --events <e> # Create a webhook
xeroctl webhooks <uuid> --update --url <url> # Update a webhook
xeroctl webhooks <uuid> --delete # Delete a webhook
xeroctl webhooks <uuid> --test # Send a test event
xeroctl webhooks <uuid> --deliveries # List delivery history
list
List all webhook subscriptions for the project. This is the default action when no ID or action flag is given.
xeroctl webhooks
xeroctl webhooks --limit 50
xeroctl webhooks --after 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10
Options
| Option | Description |
|---|---|
--limit <n> |
Maximum number of results (default 20, server cap 100) |
--after <cursor> |
Pagination cursor: webhook UUID to start after |
Output columns: ID, URL, EVENTS, ACTIVE, CREATED. Webhook IDs are bare UUIDs (no whk_ prefix).
get
Show details of a specific webhook subscription. Provides URL, subscribed events, active state, and creation and update timestamps. The signing secret is not displayed here: it is returned exactly once in the create response and never re-exposed. If you lost it, delete the webhook and create a new one.
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 -o json
create
Create a new webhook subscription. Both --url and --events are required. The webhook is active by default unless --inactive is specified.
# Create a webhook for batch events
xeroctl webhooks --create \
--url https://example.com/hooks/xerotier \
--events batch.completed,batch.failed
# Create in inactive state
xeroctl webhooks --create \
--url https://example.com/hooks/xerotier \
--events response.completed,response.failed \
--inactive
# Dry-run (validate without creating)
xeroctl webhooks --create \
--url https://example.com/hooks/xerotier \
--events agent.enrolled \
--dry-run
Options
| Option | Description |
|---|---|
--url <url> |
Webhook delivery URL (required) |
--events <events> |
Comma-separated event types to subscribe to (required) |
--active |
Set webhook to active state (default) |
--inactive |
Create webhook in inactive state |
--dry-run |
Validate inputs and show what would be created without persisting |
Signing secret: The server auto-generates a 32-byte hex signing secret when the webhook is created and returns it exactly once in the create response. Store it immediately; subsequent xeroctl webhooks <id> calls will not display it. The signing secret cannot be supplied or rotated; to change it, delete the webhook and create a new one.
Delivery Headers
Every delivery carries three vendor headers in addition to Content-Type: application/json. Subscribers verify by recomputing the HMAC and comparing in constant time.
| Header | Value |
|---|---|
X-Webhook-ID |
UUID of the delivery attempt (not the webhook). Use as an idempotency key. |
X-Webhook-Timestamp |
Unix epoch seconds at signing time. Reject deliveries older than five minutes. |
X-Webhook-Signature |
HMAC-SHA256(secret, timestamp + "." + raw_body), hex-encoded. |
Payload envelope (id, object, type, created_at, data) and verification snippets in Python, Node, and Swift are documented in the Webhooks API reference.
update
Update an existing webhook. All fields are optional, only the provided fields are changed.
# Update the URL
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --update --url https://new.example.com/hook
# Change subscribed events
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --update --events response.completed,batch.completed,file.uploaded
# Activate or deactivate
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --update --active
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --update --inactive
# Dry-run (preview the change without persisting)
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --update --inactive --dry-run
Options
| Option | Description |
|---|---|
--url <url> |
New webhook delivery URL |
--events <events> |
Comma-separated replacement event type list |
--active |
Set webhook to active |
--inactive |
Set webhook to inactive |
--dry-run |
Show what would change without persisting the update |
State flag conflict: --active and --inactive cannot be used together. (Action-flag exclusivity is covered in Overview.)
Cannot change the signing secret: Update does not accept a --secret flag and the server has no field to change the signing secret. To rotate, delete the webhook and create a new one (the create response will return the new secret exactly once).
delete
Delete a webhook subscription. A confirmation prompt is shown by default.
# With confirmation prompt
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --delete
# Skip confirmation
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --delete --force
# Dry run
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --delete --dry-run
Options
| Option | Description |
|---|---|
--force |
Skip the confirmation prompt |
--dry-run |
Show what would be deleted without making changes |
test
Send a test event to the webhook endpoint. Useful for verifying connectivity and payload handling before relying on live events.
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --test
On success, the command prints the HTTP status code returned by your endpoint. On failure, an error message is displayed.
Dry run: Passing --dry-run will show what would happen without sending the test event.
Rate limit: The test endpoint is rate-limited to 10 invocations per hour per webhook.
deliveries
List the delivery history for a webhook. Shows each delivery attempt with event type, HTTP status code, success status, and timestamp.
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --deliveries
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --deliveries --limit 50
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --deliveries --after 7b2d4c1a-9e3f-4a8b-bc56-1f0e8d3a4b2c
Options
| Option | Description |
|---|---|
--limit <n> |
Maximum number of delivery records to return (default 20, server cap 100) |
--after <cursor> |
Pagination cursor: delivery UUID to start after |
Output columns: ID, EVENT_TYPE, STATUS (HTTP code), SUCCESS, CREATED. The higher-level delivery state (pending, delivered, failed, exhausted) is currently only exposed via the REST API.
Event Types
Pass event type names as a comma-separated string to --events. Unknown event types are rejected by the server with a 400 error. The canonical list (grouped by family) is below.
Batch (3)
| Event Type | Description |
|---|---|
batch.completed | A batch job completed successfully. |
batch.failed | A batch job failed. |
batch.cancelled | A batch job was cancelled. |
Response (2)
| Event Type | Description |
|---|---|
response.completed | A response completed successfully. |
response.failed | A response failed. |
File (2)
| Event Type | Description |
|---|---|
file.uploaded | A file was uploaded. |
file.deleted | A file was deleted. |
Conversation (2)
| Event Type | Description |
|---|---|
conversation.created | A conversation was created. |
conversation.deleted | A conversation was deleted. |
Exec / XEM (15)
| Event Type | Description |
|---|---|
exec.dispatched | A XEM tool invocation was dispatched to an execution agent. |
exec.completed | A XEM tool invocation completed successfully. |
exec.failed | A XEM tool invocation failed (non-zero exit or transport error). |
exec.timeout | A XEM tool invocation exceeded its declared timeout. |
exec.ambiguous | A XEM invocation target was ambiguous and needs operator resolution. |
exec.approval_requested | An approval request was enqueued for a destructive invocation. |
exec.approved | An approval request was approved. |
exec.rejected | An approval request was explicitly rejected. |
exec.approval_escalated | An approval request was escalated to the next contact. |
exec.approval_timed_out | An approval request timed out without a decision. |
exec.agent_enrolled | A XEM execution agent completed enrollment. |
exec.agent_offline | A XEM execution agent transitioned to offline. |
exec.discovery_pending | A XEM discovery request is awaiting operator action. |
exec.workspace_created | An operational workspace was created. |
exec.workspace_budget_exhausted | A workspace consumed its inference-token budget for the current window. |
Agent (5)
| Event Type | Description |
|---|---|
agent.created | An agent record was created via the management API. |
agent.updated | An agent record was updated via the management API. |
agent.deleted | An agent was soft-deleted via the management API. |
agent.enrolled | An agent finished enrollment and is eligible for dispatches. |
agent.key_rotated | An agent's CURVE transport keypair rotated. |
Join Key (2)
| Event Type | Description |
|---|---|
join_key.created | A new join key was minted via the management API. |
join_key.revoked | A join key was revoked. |
Observability (1)
| Event Type | Description |
|---|---|
ox.alert.raised | A learning invariant was violated (raised at critical severity). |
Payload envelope shape and signature verification math: see Delivery Headers on this page and the Webhooks API reference.
Examples
Create and Verify a Webhook
# Create (server returns the signing secret in the response - store it now)
xeroctl webhooks --create \
--url https://hooks.example.com/xerotier \
--events batch.completed,response.completed
# Verify the test event is delivered (use the UUID returned by create)
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --test
# Review delivery log
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --deliveries
Temporarily Disable a Webhook
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --update --inactive
# Re-enable later
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --update --active
List and Clean Up
# List all webhooks
xeroctl webhooks
# Get details of a specific webhook
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10
# Delete unused webhook
xeroctl webhooks 0f3c1a8e-2d6b-4d4e-9a17-7b4c2a9d8e10 --delete --force