Loading…
We use a strictly-necessary cookie to keep you signed in. Accept all also allows optional cookies for analytics, our in-app support chat, and marketing (including ad audience cookies and email open tracking). See our Privacy Policy for details. You can change your choice anytime under Settings → Privacy.
When a counterparty's verify-access request includes enableRuntimeChallenge: true AND the endpoint declared requiresRuntimeChallenge: true in its dashboard policy, the AstraSync platform fires a one-shot HTTP probe against your agent's registered apiEndpoint. Your agent acknowledges; AstraSync records the result on the verification event for trust scoring; depending on whether the endpoint set runtime-challenge as required or optional, the result may or may not flip the recommendation.
/astrasync/challenge to your registered apiEndpoint. Your apiEndpoint should be your base URL only (e.g. https://my-agent.example.com). Do not include /astrasync or /astrasync/challenge in it. If you register with https://my-agent.com/astrasync, the platform will POST to https://my-agent.com/astrasync/astrasync/challenge — a 404. If you are getting 404s on challenge, check your registered apiEndpoint.The SDK exports a ready-to-mount handler. Minimal setup:
import express from 'express';
import { ChallengeHandler } from '@astrasyncai/verification-gateway/agent';
const app = express();
app.use(express.json());
const handler = new ChallengeHandler({ agentId: 'ASTRA-your-id' });
// Mount the challenge endpoint — AstraSync POSTs here during verify-access
app.post('/astrasync/challenge', handler.expressMiddleware());
app.listen(8080);The handler validates payload shape, checks expiry, returns the right HTTP status, and produces the response body in the format the platform expects. If you are on a non-Node stack, the contract sections below are the wire-level spec.
By default, the handler auto-includes the incoming counterpartyId and counterpartyUrl from the challenge payload in the pendingCounterparties response. This means challenges pass without any prior setup — the agent confirms the counterparty it is currently being verified against.
Agents that know their counterparties ahead of time can pre-register them. When the pre-registered list is non-empty, only those counterparties are included in the response (the auto-include is bypassed).
// Before interacting with a known counterparty
handler.registerPending('ASTRAE-counterparty-id');
// After interaction is complete
handler.removePending('ASTRAE-counterparty-id');Agents using raw HTTP can implement the handler as a single POST endpoint. Echo the challengeId and include the incoming counterpartyId in pendingCounterparties:
app.post('/astrasync/challenge', (req, res) => {
const { challengeId, counterpartyId, counterpartyUrl } = req.body;
res.json({
challengeId,
acknowledged: true,
pendingCounterparties: [counterpartyId || counterpartyUrl].filter(Boolean),
respondedAt: new Date().toISOString(),
});
});When registering, include your apiEndpoint URL if you know it. If you do not know your public URL (e.g. you are running locally), leave it blank — your owner can add it when approving your registration. Do not guess the URL — an incorrect URL causes challenge failures and access denials.
AstraSync POSTs to <your-agent-apiEndpoint>/astrasync/challenge with Content-Type: application/json and a body shaped:
{
"challengeId": "a8f3c0b1-…", // fresh UUID, single-use
"type": "pending_verification",
"counterpartyId": "ASTRAE-…" | null, // present when call originated with counterpartyId
"counterpartyUrl": "https://…" | null, // present when call originated with counterpartyUrl
"question": "Confirm this counterparty is in your pending interaction list",
"issuedAt": "2026-05-13T12:00:00Z", // ISO 8601
"expiresAt": "2026-05-13T12:00:15Z" // ISO 8601 — typically 15-60s out
}Curl probe (what an external test against your endpoint looks like):
curl -X POST https://your-agent.example/astrasync/challenge \
-H "Content-Type: application/json" \
-d '{
"challengeId": "a8f3c0b1-1234-5678-9abc-def012345678",
"type": "pending_verification",
"counterpartyId": "ASTRAE-vCSpmS2N0RX0JgeuxtB8Ew",
"counterpartyUrl": "https://gadget-emporium.example",
"question": "Confirm this counterparty is in your pending interaction list",
"issuedAt": "2026-05-13T12:00:00Z",
"expiresAt": "2026-05-13T12:00:15Z"
}'Your agent returns:
HTTP/1.1 200 OK
Content-Type: application/json
{
"challengeId": "a8f3c0b1-…", // echo the request's challengeId verbatim
"acknowledged": true, // your agent confirms the pending interaction
"pendingCounterparties": [ // current list (minimal — see "What this proves" below)
"ASTRAE-vCSpmS2N0RX0JgeuxtB8Ew",
"ASTRAE-aBcDeFgHiJkLmNoPqRsTuV"
],
"respondedAt": "2026-05-13T12:00:00.842Z" // ISO 8601 — your wall-clock at response time
}HTTP status semantics:
200 — challenge acknowledged. Platform records status: 'passed' on the verification event.400 — malformed (missing fields, invalid shapes). Platform records status: 'failed'.410 — challenge expired (you got it after expiresAt). Platform records status: 'failed'.status: 'failed'.status: 'timeout'.The runtime-challenge protocol is currently v1: plain HTTP, no cryptographic signing. A successful response demonstrates that your agent's apiEndpoint is reachable, that the agent-side process is aware of the pending counterparty, and that the single-use challenge lifecycle works end-to-end. Combined with the agent's verified registration and the platform's trust-scoring signals, this is sufficient observability for the round-13 trust tiers.
Cryptographic upgrade path: AstraSync is shipping DPoP RFC 9449 as the next phase. Agents will declare a public key at registration, sign challenge responses with the corresponding private key, and the platform will verify the signature before recording the result. This is the structural fix that elevates the v1 challenge from an observability signal to a cryptographic attestation. No partner action required pre-shipping; the DPoP enrolment will be additive, not breaking.
Per-purpose default timeouts in RuntimeChallengeService.TIMEOUTS:
financial_transaction, payment — 30sdelegate_task, data_migration, research — 60sCounterparty SDK can override per-call via runtimeChallengeOptions.timeoutOverride (clamped 30-120s). The platform records latencyMs on the response — time from challenge sent to your agent's response received.
challengeId is a fresh UUID per challenge, generated platform-side. It's single-use: AstraSync correlates the request and response via this id, then closes out the challenge record. Your agent must echo the same id verbatim on the response — a mismatch fails the challenge.
The pendingCounterparties array your agent returns is intentionally minimal. It's an acknowledgment of awareness, not a cryptographic proof. Trust comes from the verify-access decision chain (PDLSS + attestations + trust score + endpoint policy), not from the challenge response in isolation. Don't treat the challenge as a primary trust signal pre-DPoP.
Endpoint owners toggle this per-endpoint in the dashboard:
enableRuntimeChallenge: true) — for trust scoring + observability — but a failure or timeout does NOT flip the verify-access recommendation. The result still lands on the response payload's runtimeChallenge block.deny; timeout → recommendation step_up_required. Passed → no change to the existing recommendation.Round-14 (Item 1) moved the F8 gate from the SEND of the challenge to the RECOMMENDATION outcome — round-12 had it on SEND which suppressed trust-scoring on optional. See round-14 adapter-spec entry for the full context.