Skip to content

Managing Subscriptions

Once a subscription is created, you can list, inspect, update, pause, resume, and delete it through the wh sub CLI commands, the MCP subscription tools, or the HTTP API.

Terminal window
wh sub list

Output shows each subscription’s name, kind, active state, and (for cron) the cronspec. For cross-repo subscriptions, a ← org/repo marker indicating the source repo being watched is shown when you have read access to that source repo:

Subscriptions: myorg/myrepo
signal-hook [webhook] active
daily-sync [cron→sprite] active 0 8 * * *
upstream-hook [sprite] active ← myorg/otherrepo
{
"name": "warmhub_subscription_list",
"arguments": {
"orgName": "myorg",
"repoName": "myrepo"
}
}
Terminal window
GET /api/repos/myorg/myrepo/subs
Terminal window
wh sub view signal-hook

Returns the subscription’s kind, active state, webhook URL (if webhook), cron configuration (if cron), and for subscriptions executed by sprite the action container name and configuration (command, githubRepo, ref, inputMode). When present, token-scoped sprite executions, including cron subscriptions with executorKind: "sprite", also show their configured token scope entries.

For cross-repo subscriptions, a source repo: field is shown when you have read access to the source repo, indicating which repo’s events trigger the subscription:

upstream-hook
kind: sprite
active: true
source repo: myorg/otherrepo
action container: wh-warmdex-action-test
command: bun run action
githubRepo: warmdex/action-test
ref: main
inputMode: stdin
{
"name": "warmhub_subscription_get",
"arguments": {
"orgName": "myorg",
"repoName": "myrepo",
"name": "signal-hook"
}
}
Terminal window
GET /api/repos/myorg/myrepo/subs/signal-hook

Pausing a subscription stops all new deliveries. Existing in-flight deliveries complete normally.

Terminal window
# Pause
wh sub pause signal-hook
# Resume
wh sub resume signal-hook

For cron subscriptions, pausing deregisters the cron job entirely — no ticks fire while paused. Resuming re-registers the job with the original cronspec and timezone. Ticks that would have fired during the pause period are not retroactively delivered.

{
"name": "warmhub_subscription_pause",
"arguments": {
"orgName": "myorg",
"repoName": "myrepo",
"name": "signal-hook"
}
}
Terminal window
POST /api/repos/myorg/myrepo/subs/signal-hook/pause
POST /api/repos/myorg/myrepo/subs/signal-hook/resume

Use update when the subscription should keep the same name and lifecycle state, but its trigger or executor configuration needs to change. Provided fields patch the existing subscription, and nested spriteConfig / cronConfig keys merge into the current config.

Token scopes are not part of the update surface. If a sprite subscription’s minted token scopes need to change, delete and recreate the subscription with the new tokenScopes.

Terminal window
wh sub update sprite-hook \
--on Signal \
--filter '{"shape":"Signal","operation":"add"}' \
--command 'bun run action' \
--github-repo warmdex/action-test \
--ref main \
--input-mode stdin

For cron subscriptions, switch schedules or executor settings the same way:

Terminal window
wh sub update health-check \
--cronspec "*/30 * * * *" \
--executor webhook \
--webhook-url https://example.com/health
{
"name": "warmhub_subscription_update",
"arguments": {
"orgName": "myorg",
"repoName": "myrepo",
"name": "sprite-hook",
"shapeName": "Signal",
"filterJson": {
"shape": "Signal",
"operation": "add"
},
"spriteConfig": {
"command": "bun run action",
"githubRepo": "warmdex/action-test",
"ref": "main",
"inputMode": "stdin"
}
}
}
Terminal window
PATCH /api/repos/myorg/myrepo/subs/sprite-hook

Lifecycle changes still go through pause and resume, and credential bindings remain managed via the bind/unbind endpoints.

Deleting a subscription permanently removes it along with its credential bindings and cron schedule.

Terminal window
wh sub delete signal-hook
{
"name": "warmhub_subscription_delete",
"arguments": {
"orgName": "myorg",
"repoName": "myrepo",
"name": "signal-hook"
}
}
Terminal window
DELETE /api/repos/myorg/myrepo/subs/signal-hook

The delivery feed shows the history of action deliveries for a subscription — what was dispatched, when, and what happened.

Terminal window
wh sub log signal-hook

Output shows each delivery’s run status, attempt count, timing, associated commit, and matched operation indexes. For sprite subscriptions, the action container name is shown at the top. Failed runs display the error code and message:

Subscription: signal-hook
Action container: wh-warmdex-action-test
succeeded 1/1 2m ago commit a1b2c3d ops[0,1]
[0] add thing Sensor/temp-1
[1] add assertion Reading/temp-1-v1
dead_letter 3/5 15m ago commit e4f5a6b ops[0]
SPRITE_EXIT_NONZERO: command exited with status 1
[0] revise thing Sensor/temp-1

Follow deliveries in real time with --live:

Terminal window
wh sub log signal-hook --live

This opens a WebSocket connection that auto-refreshes as new deliveries arrive.

{
"name": "warmhub_action_livefeed",
"arguments": {
"orgName": "myorg",
"repoName": "myrepo",
"subscriptionName": "signal-hook",
"limit": 20
}
}

The limit parameter controls how many deliveries to return (1–200, default 50). Pagination is supported via the cursor field in the response.

The HTTP API provides repo-level run listing (not subscription-scoped):

Terminal window
GET /api/repos/myorg/myrepo/actions/runs?status=failed_terminal&limit=20

For subscription-scoped delivery feeds, use the CLI (wh sub log) or MCP (warmhub_action_livefeed).

Each delivery can have multiple attempts if retries are needed. To inspect the attempt history for a specific delivery:

Terminal window
wh sub attempts signal-hook a1b2c3d

Output shows each attempt’s status, duration, HTTP status (for webhooks), and error details:

Attempts: signal-hook commit a1b2c3d
#1 failed (12000ms) SPRITE_EXIT_NONZERO: command exited with status 1
#2 failed (8000ms) SPRITE_EXIT_NONZERO: command exited with status 1
#3 failed (15000ms) SPRITE_EXIT_NONZERO: command exited with status 1
{
"name": "warmhub_action_attempts",
"arguments": {
"orgName": "myorg",
"repoName": "myrepo",
"subscriptionName": "signal-hook",
"commitId": "a1b2c3d4e5f6a7b8"
}
}

Each attempt records:

FieldDescription
attemptAttempt number (1-based)
statusstarted, succeeded, or failed
executorKindwebhook or sprite
startedAtTimestamp when the attempt began
finishedAtTimestamp when the attempt completed (if finished)
httpStatusHTTP response status (for webhooks)
errorCodeError classification code
errorMessageHuman-readable error description
StatusMeaning
pendingRun created, not yet executed
runningCurrently executing
retry_waitFailed, waiting for next retry attempt
succeededCompleted successfully
failed_terminalNon-retryable error (no further attempts scheduled)
dead_letterAll retries exhausted without success

WarmHub records repo-scoped action failure notifications when a delivery ends in failed_terminal or dead_letter. These are delivery-failure records, not the cross-repo user notification feed shown in the web app.

Terminal window
wh notifications --repo myorg/myrepo

Filter by time with either epoch milliseconds or an ISO timestamp:

Terminal window
wh notifications --repo myorg/myrepo --since 2026-03-30T12:00:00Z
{
"name": "warmhub_action_notifications",
"arguments": {
"orgName": "myorg",
"repoName": "myrepo",
"limit": 20
}
}

The MCP tool is also repo-scoped and returns delivery-failure notification records rather than the web app’s user feed. When a run reaches failed_terminal or dead_letter status, WarmHub creates an inbox notification with the error details. Success notifications can also be enabled per-subscription — see Subscriptions Overview. Failure notifications are visible through the action notification queries:

Terminal window
GET /api/repos/myorg/myrepo/actions/notifications

Common error codes you may see in attempt records:

CodeRetryableDescription
WEBHOOK_NETWORK_ERRORYesNetwork error connecting to webhook URL
SPRITE_AUTH_MISSINGNoBackend missing required API key for sprite execution
SPRITE_CREATE_FAILEDMaybeFailed to create execution environment
SPRITE_EXECUTION_FAILEDMaybeCommand execution failed
SPRITE_EXIT_NONZEROMaybeCommand exited with non-zero status
SPRITE_EXEC_HTTP_ERRORMaybeHTTP error communicating with execution backend
WEBHOOK_INPUT_NOT_FOUNDNoCould not load execution input for delivery