Agents: sign in with the Colony
Autonomous agents on The
Colony can skip the button above and authenticate
non-interactively, in two steps. First, at the Colony,
exchange your own agent credential for an
id_token minted for AgentDisco — OAuth 2.0
Token Exchange
(RFC 8693),
audience colony_gNvs-06hD2sPmBWHgQ4skwGUMpDwqmcl.
Then present that id_token here — never your raw
Colony credential; only a token minted for AgentDisco is
accepted. No browser, no redirect. The minted key is the
authenticated tier (500 scans/day) and is bound to your
Colony identity.
curl -X POST https://agentdisco.io/api/v1/auth/colony/agent \
-H "Content-Type: application/json" \
-d '{"id_token":"<your pre-exchanged id_token>"}'
The response carries an ak_… token (shown once) —
present it as Authorization: Bearer <token>
on subsequent /api/v1/* calls, exactly like a key
minted above. Human Colony accounts use
Log in with the Colony
on the website instead; this endpoint is agent-only.
Webhooks
Get a signed JSON POST to a URL of your choice every
time a scan of a host you registered completes. Useful
for CI integrations, status-page updates, or pushing
grade changes into your own dashboards.
Setup
Sign in, open your
account, scroll to Scan webhooks, fill in
the host you want to subscribe to + the receiver URL,
and submit. We mint a 32-byte HMAC signing secret and
show it to you exactly once — copy it into your
receiver's secret store.
Payload shape
On every completed scan we POST a JSON body that looks
like this:
POST https://your-receiver.example/agent-disco
Content-Type: application/json
X-Agent-Disco-Event: scan.completed
X-Agent-Disco-Webhook-Id: 019d...
X-Agent-Disco-Signature: sha256=...
{
"event": "scan.completed",
"scan": {
"id": "019d...",
"host": "your-site.example",
"grade": "B",
"score": 72,
"completedAt": "2026-04-25T10:00:00+00:00",
"statusUrl": "/api/v1/scans/019d...",
"resultUrl": "/report/your-site.example"
}
}
Verifying signatures
Every payload carries an X-Agent-Disco-Signature
header of the form sha256=<hex>.
Recompute HMAC-SHA256(secret, raw_body)
and compare in constant time:
# Python
import hmac, hashlib
def verify(body: bytes, signature: str, secret: str) -> bool:
expected = "sha256=" + hmac.new(
secret.encode(), body, hashlib.sha256,
).hexdigest()
return hmac.compare_digest(expected, signature)
Retries + auto-pause
We expect a 2xx response within 10 seconds. Anything
else (4xx, 5xx, timeout, DNS failure) is a delivery
failure that retries 3× with exponential backoff. After
5 consecutive terminal failures we auto-pause the
webhook — the row stays in your account but no further
deliveries fire. Resume by deleting + re-creating it,
or by ensuring the next attempt succeeds (the counter
resets on any 2xx).
Replay protection
The scan.id in every payload is a UUIDv7
— its embedded timestamp lets your receiver reject
replays older than a window you choose (we recommend
5 minutes). The signature alone doesn't include a
nonce; if you need stricter replay protection,
discard payloads whose scan.completedAt
is older than your tolerance.