Trigger agents, read run status, and manage approvals from your own code, Zapier, CI pipeline, or any HTTP client.
Bearer auth
Keys start with ak_. Generate in Settings → API keys.
60 req/min per key
Responses include X-RateLimit-Remaining. Burst over the limit and you get 429 with a Retry-After header.
Scoped keys
read, run, admin. Give each integration the minimum it needs.
Send your API key as a bearer token. The organization is resolved from the key — you don't need to pass an org ID.
curl https://app.revvedagents.ai/api/v1/agents \ -H "Authorization: Bearer ak_YOUR_KEY_HERE"
/api/v1/agentsscope: readList every active agent in the catalogue.
/api/v1/agents/{slug}/runsscope: runTrigger an agent run. Optional body: recordObjectType, recordId, config. config keys are filtered by a per-agent allowlist; anything rejected comes back as droppedConfigKeys on the 202. Send an Idempotency-Key to make a retry safe.
/api/v1/runs/{id}scope: readGet a run's status, progress, and results.
/api/v1/runs/{id}/cancelscope: runCancel a queued or running run. Cooperative — a running agent stops at its next checkpoint. A run that already finished returns 200 with alreadyTerminal: true.
/api/v1/approvalsscope: readList approvals. Query: ?status=pending|executing|approved|rejected|auto_rejected|request_changes, ?limit=50 (max 200).
/api/v1/approvals/{id}/approvescope: adminApprove a pending approval and execute the underlying action.
/api/v1/approvals/{id}/rejectscope: adminReject a pending approval. Body: { reason?: string }.
curl -X POST https://app.revvedagents.ai/api/v1/agents/deal-risk-autopilot/runs \
-H "Authorization: Bearer ak_YOUR_KEY_HERE" \
-H "Content-Type: application/json" \
-d '{ "recordObjectType": "deal", "recordId": "12345" }'
# → 202 Accepted
# { "success": true, "data": { "runId": "...", "status": "queued" } }401 — missing or invalid bearer token.403 — key lacks the required scope for that endpoint.404 — resource not visible to this org.429 — rate limit exceeded; inspect Retry-After.400 — the request could not be acted on; for a run, usually no active HubSpot connection.409 — a run for that agent and record is already in flight. Wait for it, cancel it, or retry with the same Idempotency-Key.422 — an Idempotency-Key was reused with a different request body.5xx — transient; retry with backoff, and send the same Idempotency-Key so the retry cannot start a second run.Starting a run is the one mutating call in this API, so it accepts an Idempotency-Key header — any string up to 256 characters, a UUID by convention. The first request with a key runs normally and its 202 response is stored. A later request with the same key on the same endpoint replays that exact response with an Idempotent-Replayed: true header and does not start a second run. Keys are scoped to the API key that used them and to the endpoint they were used on, and they expire after 24 hours. Reusing a key on the same endpoint with a different body returns 422 rather than replaying a response that no longer describes what you asked for.
Subscribe to events at Settings → Webhooks. Each delivery is a POST with a JSON body and three headers: X-RevvedAgents-Event (event name), X-RevvedAgents-Signature (HMAC-SHA256 of the raw body, keyed by your endpoint secret, formatted sha256=<hex>) and X-RevvedAgents-Delivery-Id (stable across retries of the same delivery — use it to deduplicate).
Failed deliveries retry with exponential backoff — 30s, 2m, 15m, 1h — up to five attempts. 5xx, 429, 408 and network errors are retried; 400, 401, 403, 404, 405, 410 and 422 are treated as permanent and are never retried. A delivery we refuse to send at all — an endpoint URL that no longer passes our outbound safety check — is also not retried. After five consecutive failed deliveries the endpoint is marked failed and stops receiving events until you re-enable it.
Every delivery is wrapped in an envelope. The payload described for each event below is the contents of data; event, deliveryId and timestamp are always present.
{
"event": "agent.run.completed",
"deliveryId": "66f0a1c2d3e4f5a6b7c8d9e0",
"timestamp": "2026-09-13T10:04:11.482Z",
"data": {
"runId": "66ef9b8a7c6d5e4f3a2b1c0d",
"agentSlug": "deal-risk-autopilot",
"summary": "Reviewed 51 open deals; 12 need attention.",
"score": 72,
"findingsCount": 4,
"completedAt": "2026-09-13T10:04:11.121Z"
}
}agent.run.completedAn agent run finished and produced output. `data` includes runId, agentSlug, summary, score, findingsCount, completedAt.
agent.run.failedAn agent run ended without producing output. `data` includes runId, agentSlug, error, category, transient, hint, failedAt.
agent.run.cancelledA queued or running run was cancelled, in the app or through the API. `data` includes runId, agentSlug, previousStatus, reason, cancelledAt.
approval.createdA run parked and is waiting for someone to review its proposed changes. `data` includes approvalId, executionId, agentSlug, action, expiresAt.
approval.approvedA reviewer approved a proposed change and it was executed. `data` includes approvalId, executionId, agentSlug, reviewedBy, reviewedAt.
approval.rejectedA reviewer rejected a proposed change. Nothing was written. `data` includes approvalId, executionId, agentSlug, reviewedBy, reviewedAt.
approval.similar_bulk_appliedOne decision was applied to a group of similar approvals at once. `data` includes anchorApprovalId, appliedCount, decision, reviewedBy.
finding.criticalA run produced a critical finding. `data` includes runId, agentSlug, type, message, severity, details.
finding.exportedA finding was exported to HubSpot as a task or a note. `data` includes findingType, objectType, objectId, exportKind.
hubspot.connection.disconnectedA HubSpot connection for this org went away. Two shapes: an admin disconnecting in-app, or HubSpot reporting an uninstall. `data` includes connectionId, portalId, disconnectedAt (in-app) — or portalIds[], uninstalledAt, source (uninstall).
import crypto from "crypto";
export function verifyRevvedAgentsWebhook(req, rawBody, secret) {
const sent = req.headers["x-revvedagents-signature"];
const expected =
"sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex");
const a = Buffer.from(sent || "", "utf8");
const b = Buffer.from(expected, "utf8");
return a.length === b.length && crypto.timingSafeEqual(a, b);
}Always compute the HMAC over the raw request body, before any JSON parsing. Reject any request where the signature doesn't match — the event payload may have been tampered with.
Full machine-readable spec: /api/v1/openapi.json. Drop it into Postman, Stoplight, or your favorite SDK generator.