Skip to content

Actions

This page covers the HTTP endpoints you can use to inspect subscription delivery runs, inspect attempt history, read repo-scoped action notifications, and post callback status updates from your webhook handler.

To create, update, pause, or remove subscriptions, use the CLI and MCP workflows or the SDK client.subscription surface. Subscription management REST endpoints under /api/repos/:orgName/:repoName/subs are not currently available.

Accessing action history requires a token with repo:configure scope. repo:configure is the admission gate for these routes — callers without it receive an opaque 404. Whether the caller also holds effective repo:read access determines what appears inside each run row. A narrowed token is one created with allowedMatches patterns that restrict which refs it can read — see token scopes for how those patterns are declared and enforced.

  • With unrestricted repo:read: Run rows include the full matchedOperationIndexes array and free-form diagnostics. On run rows that means the error message; response snippets are carried on attempt rows and in the live feed, not on run rows.
  • With narrowed repo:read (scoped PAT with allowedMatches): Run rows are still returned — with statuses, counts, and timestamps — but matchedOperationIndexes is filtered down to only the operations the caller can read, and free-form diagnostics are stripped.
  • Without repo:read: Run rows are still returned — with statuses, counts, and timestamps — but matchedOperationIndexes is emptied and free-form diagnostics are stripped.

Pagination metadata (such as nextCursor) is part of the page envelope, not the individual run rows, and is unaffected by read-scope narrowing.

GET /api/repos/:orgName/:repoName/actions/runs

Section titled “GET /api/repos/:orgName/:repoName/actions/runs”

List action runs for a repository, optionally filtered by subscription name, status, outcome, or exact run ID.

Auth: Required — repo:configure scope. Anonymous callers, under-scoped tokens, and missing repositories all return an opaque 404 with a Vary: Authorization response header so existence is not disclosed; authenticate with repo:configure to see real responses.

Scoped PAT filtering: If your token is a scoped PAT, the list is automatically filtered to runs belonging to subscriptions whose Subscription/<name> refs fall within the PAT’s allowed matches. Runs outside that scope are not returned — you will not receive an error, just a narrower result set. A run lookup for an out-of-scope run follows the same opaque 404 path as an unauthenticated request.

ParameterTypeRequiredDescription
subscriptionNamestringNoFilter by subscription name
runIdUUID stringNoExact-match filter that limits results to at most one run. Must be a UUID-formatted action run identifier — non-UUID values are rejected with 400 VALIDATION_ERROR. All other filters (subscriptionName, status, outcome, since, cursor) remain active and can still narrow the result when runId is present.
statusenumNoFilter by status. Must be one of pending, running, processing, retry_wait, succeeded, failed_terminal, dead_letter, or suppressed. Any other value returns 400 VALIDATION_ERROR. Cannot be combined with outcome.
outcomeenumNoFilter by outcome. Must be one of succeeded or failed. failed is a coarse filter that matches both failed_terminal and dead_letter runs — there is no literal run status named failed. Any other value returns 400 VALIDATION_ERROR. Cannot be combined with status.
cursorstringNoPagination cursor returned as nextCursor in a previous response. Cannot be combined with since.
sinceintegerNoRuns created after this epoch-milliseconds timestamp. Cannot be combined with cursor.
limitintegerNoMaximum runs to return per page. Capped at 200 — values above 200 are rejected with a validation error.

Passing both status and outcome together, or both since and cursor together, returns 400 VALIDATION_ERROR. These mutual-exclusion rules apply regardless of whether runId is also present — for example, ?runId=...&status=failed_terminal&outcome=failed is still rejected, and ?runId=...&since=...&cursor=... is still rejected.

The response is a page envelope. Use nextCursor in a subsequent request to retrieve the next page; when nextCursor is absent, you have reached the last page.

{
"items": [
{
"subscriptionName": "signal-hook",
"runId": "019d90f0-1111-7000-8000-000000000001",
"status": "succeeded",
"matchedOperationIndexes": [0, 1],
"attemptCount": 1,
"maxAttempts": 5,
"createdAt": 1741132800000,
"updatedAt": 1741132801000
}
],
"nextCursor": "opaque-cursor-string"
}

Failed runs include lastErrorCode; lastErrorMessage is available only to effective full-repository readers.

Terminal window
curl -H "Authorization: Bearer $WH_TOKEN" \
"https://api.warmhub.ai/api/repos/myorg/myrepo/actions/runs?status=failed_terminal"

To fetch one exact run by ID:

Terminal window
curl -H "Authorization: Bearer $WH_TOKEN" \
"https://api.warmhub.ai/api/repos/myorg/myrepo/actions/runs?runId=019d90f0-1111-7000-8000-000000000001"

To page through results, pass the nextCursor value from each response as the cursor parameter on the next request:

Terminal window
curl -H "Authorization: Bearer $WH_TOKEN" \
"https://api.warmhub.ai/api/repos/myorg/myrepo/actions/runs?cursor=opaque-cursor-string"

GET /api/repos/:orgName/:repoName/actions/runs/:runId/attempts

Section titled “GET /api/repos/:orgName/:repoName/actions/runs/:runId/attempts”

Get the attempt history for a specific action run.

Auth: Required — repo:configure scope. Anonymous callers, under-scoped tokens, and missing repositories all return an opaque 404 with a Vary: Authorization response header so existence is not disclosed. Authenticated callers with access receive a structured 404 when the requested run does not exist.

Scoped PAT filtering: If your token is a scoped PAT, a run whose Subscription/<name> ref falls outside the PAT’s allowed matches is treated as not found and returns the same opaque 404 as an unauthenticated request.

ParameterTypeDescription
runIdstringAction run identifier
Terminal window
curl -H "Authorization: Bearer $WH_TOKEN" \
"https://api.warmhub.ai/api/repos/myorg/myrepo/actions/runs/019d90f0-1111-7000-8000-000000000001/attempts"

GET /api/repos/:orgName/:repoName/actions/notifications

Section titled “GET /api/repos/:orgName/:repoName/actions/notifications”

List repo-scoped action notification records.

Auth: Required — repo:configure scope. Anonymous callers, under-scoped tokens, and missing repositories all return an opaque 404 with a Vary: Authorization response header so existence is not disclosed; authenticate with repo:configure to see real responses.

Scoped PAT filtering: If your token is a scoped PAT, notifications are filtered to those whose Subscription/<name> refs fall within the PAT’s allowed matches. Notifications outside that scope are silently excluded from the result set.

ParameterTypeRequiredDescription
sinceintegerNoNotifications after this epoch-milliseconds timestamp
limitintegerNoMaximum notifications to return. Capped at 200 — values above 200 are rejected with a validation error.
Terminal window
curl -H "Authorization: Bearer $WH_TOKEN" \
"https://api.warmhub.ai/api/repos/myorg/myrepo/actions/notifications?limit=20"

Report progress or completion for an asynchronous action run. This endpoint is not repo-prefixed.

In practice, runId comes from the original webhook payload, and most handlers can use the provided callback_url directly instead of constructing the path themselves. See Webhook Payload.

Auth: Required. The required scope depends on whether the callback is for a repo-scoped or org-scoped action:

  • Repo-scoped callbacks: Authorize with repo:action-callback. Tokens with repo:write are also accepted.
  • Org-scoped callbacks: Authorize with org:action-callback.

Use the narrowest applicable scope (repo:action-callback or org:action-callback) rather than a broader write token.

FieldTypeRequiredDescription
statusstringYesOne of processing, success, failure, or retry_requested
messagestringNoOptional status detail or response snippet
errorstringNoOptional human-readable error message

Callback statuses are input commands: processing maps to stored run status processing, success maps to succeeded, failure maps to dead_letter, and retry_requested maps to retry_wait. The success response body includes the actual stored runStatus after the transition.

Terminal window
curl -X POST "https://api.warmhub.ai/api/action-runs/${RUN_ID}/callback" \
-H "Authorization: Bearer ${WH_TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"status": "failure",
"error": "Unexpected field \'category\' on line 5."
}'