https://api.antigen.sh.
Authenticate every request with an organization API key in x-api-key. Keys begin with atg_sk_.
Send the key only in that header: never in a URL, a browser history, a source file, or a log. Use
content-type: application/json for Run creation and guidance.
A local caller deadline bounds only that caller. It does not create, stop, resume, or cancel a Run.
Conventions
Every response carriescontractVersion, currently "v1". Successful reads return the resource
directly; errors return an error object described under Errors.
Each endpoint requires a scope on the credential. See Authentication for how
credentials are issued and how authorization errors are resolved.
Two endpoints accept query parameters:
GET /v1/runs takes cursor, limit, and status, and
GET /v1/runs/{runId}/events takes after. Every other endpoint rejects a query string with 400
and INVALID_REQUEST, and so does an unrecognized parameter on those two. The message does not name
the offending parameter. A filter that is silently ignored is worse than a rejected request, because
a dropped status returns Runs the caller did not ask for while appearing to have succeeded.
Discovery and creation
List approved targets
GET /v1/targets
Lists targets approved for the caller’s organization.
POST /v1/runs. If creation returns
TARGET_NOT_APPROVED, re-read this endpoint rather than editing the rejected target.
Create a Run
POST /v1/runs
Creates one authorized Run for a coherent assessment objective.
id immediately with the assessment record. If the response is ambiguous, read that saved
ID with GET /v1/runs/{runId} before considering another creation request. A
second POST /v1/runs is a new assessment record, not a retry.
List and read Runs
List Runs
GET /v1/runs
Reads an organization-visible page of Runs.
nextCursor is present only when another page exists. Pass it back unchanged. Do not derive
authorization, identity, or ordering from a cursor or a Run ID.
Read a Run
GET /v1/runs/{runId}
Reads one known Run by its saved opaque ID.
startedAt appears once it is
running, stoppedAt when it is stopped, and completedAt on a terminal status. A failed Run also
carries failure with a code of EXECUTION_UNAVAILABLE or RUN_EXECUTION_FAILED and a message.
RUN_NOT_FOUND, and a
credential without runs:read answers FORBIDDEN. Read this endpoint after any ambiguous create or
lifecycle request, then resume observation with
GET /v1/runs/{runId}/events after your last handled checkpoint.
Events and findings
Stream Run events
GET /v1/runs/{runId}/events
Opens an ordered server-sent event stream for a Run. The response uses
content-type: text/event-stream and stays open until the Run reaches a terminal state or the
caller disconnects.
Resume with either a numeric after query parameter or an opaque Last-Event-ID header.
They are alternatives, and sending both is rejected with 400 and INVALID_REQUEST.
Persist
sequence only after handling that event, and resume with after=<sequence>. When you
store the opaque id instead, send it as Last-Event-ID and omit after; the two cursors are not
interchangeable. An invalid cursor is rejected with INVALID_REQUEST.
Read Run findings
GET /v1/runs/{runId}/findings
Reads durable findings and remediation guidance for one Run.
severity is one of critical, high, medium, low, or info. proof, endpoint, and cwe
appear only when available. An empty findings array is a valid outcome for a completed Run, not an
integration failure.
Guidance and lifecycle
Send guidance
POST /v1/runs/{runId}/messages
Delivers scoped guidance to an existing Run. The JSON body requires a content string; keep the
guidance within the Run’s approved target and Guardrails.
Lifecycle actions
stop, resume, and cancel all return the Run in its requested new state.
stop and resume parse a JSON body and reject a malformed one with INVALID_REQUEST, so send
{} and content-type: application/json. cancel reads no body at all. DELETE /v1/runs/{runId}
is an exact alias for cancel, for clients that prefer the verb.
INVALID_RUN_STATE means the action does not apply to the Run’s observed status, usually because
another transition already occurred. Read the Run and choose a valid action rather than repeating
the request. Resuming does not re-evaluate target approval, so confirm the scope still applies
first. A local connection failure does not prove the action was rejected.
Errors
Error responses carrycontractVersion and an error object with a stable code, a message, and
an optional requestId.
The status code carries information the
code does not, and the reverse is also true, so read both.
The line between the two authorization codes is whether the credential is allowed to do this at all,
which is FORBIDDEN, or whether the request itself is written incorrectly, which is
INVALID_REQUEST.
RUN_NOT_FOUND deliberately covers more than a missing Run. It is also the response when the Run
exists but belongs to another organization. Those two cases are not distinguishable from outside, by
design: a caller holding a Run ID cannot learn whether that ID is real. Do not use this endpoint to
test whether an ID exists, and do not report a cross-organization Run to a user as deleted. A
mistyped path is a separate code, NOT_FOUND, so a 404 about routing is never confused with a 404
about a Run.
Request bodies are validated strictly. A field the endpoint does not define is rejected with
INVALID_REQUEST rather than ignored, so a misspelled key fails loudly instead of silently dropping
the value you meant to send.
This set may grow. Handle a code you do not recognize by its HTTP status rather than by an
exhaustive match, so that a new code does not turn into an unhandled failure in your client.
Retain requestId with the saved Run ID whenever one is present. It lets support identify the
failing request without exposing credentials.
Retrying a failed request
Retry on408, 429, and any 5xx. Do not retry 400, 401, 403, 404, or 409: the request
is wrong or no longer applicable, and repeating it produces the same response. 503 with
EXECUTION_UNAVAILABLE means execution capacity is momentarily exhausted: back off and retry.
The TypeScript SDK reconnects event streams with exponential backoff from a 250ms base, capped at 5s,
scaled by random jitter between 0.5 and 1.5, for at most 5 consecutive failures. Those values are a
reasonable starting point for a hand-written client.
POST /v1/runs accepts no idempotency key. Retrying a create that failed with 503 can produce two
Runs, both of which will execute and both of which are billable. When a create is ambiguous, list
Runs and look for one matching your targets before sending it again.
After an ambiguous create, lifecycle, or observation request, do not infer the remote result from a
local failure. Preserve the Run ID and your event checkpoint, read the Run, resume events after that
checkpoint, and read findings for durable remediation work.
Related concepts: Get started, TypeScript SDK,
Guides, and Reliability and security.