Developers
One surface. The dashboard is just another client.
Everything AgentScore does runs through the versioned /v1 API — there is no private backend with extra powers. Per-company keys, a validated ingestion contract, an append-only audit trail, and an OpenAPI 3.1 document the API itself serves at GET /v1/openapi.json — generated from the same registry the write path enforces.
Quickstart
# 1. Identify your key (scopes + company binding)
curl https://api.agentscore.dev/v1/me \
-H "Authorization: Bearer $AGENTSCORE_KEY"
# 2. Push KPI events through the validated write path
curl -X POST \
https://api.agentscore.dev/v1/companies/$COMPANY/agents/$AGENT/events \
-H "Authorization: Bearer $AGENTSCORE_KEY" \
-H "Content-Type: application/json" \
-d '{
"source": "my-platform",
"events": [{
"kpiName": "task_success_rate",
"value": 87.5,
"unit": "percent",
"recordedAt": "2026-08-01",
"sourceRecordId": "batch-2026-08-01-tsr"
}]
}'
# 3. Recompute and read the scorecard
curl -X POST https://api.agentscore.dev/v1/companies/$COMPANY/recompute \
-H "Authorization: Bearer $AGENTSCORE_KEY"
curl https://api.agentscore.dev/v1/companies/$COMPANY/scorecard \
-H "Authorization: Bearer $AGENTSCORE_KEY"The ingestion contract
Validated at write time, never at scoring time
KPI names must exist in the registry, units are required and canonicalized (percent to fraction, milliseconds to seconds), and dates must be real calendar dates. A bad row rejects its whole batch with per-index problems — partial garbage never lands.
Idempotent by contract
Every event carries (agent, source, sourceRecordId). Retries, replays, and re-syncs skip what already landed and report it — double ingestion is structurally impossible, not best-effort.
Raw-first retention
Connectors land the complete upstream payload in an append-only, versioned vault before any KPI is derived. Re-derivation from history is always possible; nothing a source hands us is silently discarded.
Append-only, audited
Events, scores, and the audit trail have no update or delete anywhere in the stack — enforced by database triggers, not policy. Every mutation, denial, connect, revoke, and export is audit-logged with a request id you also get back in the x-request-id header.
No oracles
Unknown key, revoked key, wrong company — one uniform envelope. Credential verification failures return one generic error. Response shape never leaks what exists.
Enterprise access
SSO and SCIM provisioning arrive via WorkOS for organization accounts; per-company API keys with read/write/admin scopes are available today, hashed at rest and shown once at mint.
Endpoint reference
Generated from the served spec — the coverage test fails the build if a route exists that this reference doesn't document, or vice versa.
Platform
Liveness and identity.
GET/v1/healthz
The only unauthenticated route besides this spec. Touches no data.
200Service is up.
public — no auth required
GET/v1/me
Returns the key's scope class and bound company (null for platform admin keys).
200Caller identity.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
GET/v1/openapi.json
200The OpenAPI 3.1 spec.
public — no auth required
Companies
Companies and their agent fleets.
POST/v1/companies
Admin scope. Vertical determines the sector used for coarse peer cells.
required: name, vertical
201Created.
400Validation failed.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
GET/v1/companies/{companyId}
200The company.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown or deleted company.
DELETE/v1/companies/{companyId}
Admin scope. Marks the company deleted; the erasure path cascades from here.
200Soft-deleted.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
GET/v1/companies/{companyId}/agents
200The fleet.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
POST/v1/companies/{companyId}/agents
agentType keys the peer cell — it describes what the agent DOES (dispatch, sdr, support…), never its vendor.
required: name, agentType, industry
201Created.
400Validation failed.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
Ingestion
The validated KPI write path — the universal escape hatch for any agent no connector covers.
GET/v1/companies/{companyId}/agents/{agentId}/events
Paged per-agent event history, newest first, each event tagged with its registry factor. This is the evidence trail: a capped agent's policy violations, a slow agent's response times — with dates. Filter by kpiName to drill into one metric.
200Events page.
400Unknown kpiName filter.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Agent not found in this company.
POST/v1/companies/{companyId}/agents/{agentId}/events
THE write path — connectors, CSV import, and direct API calls all land here. Batches are atomic: every row is validated before any row is written; one bad row rejects the whole batch with per-index problems. Duplicate (agent, source, sourceRecordId) tuples are skipped and reported, never double-ingested. Rate KPIs must land in [0, 1] after unit canonicalization.
required: events
201Batch accepted.
400Validation failed — `problems` lists every bad row by index. Nothing was written.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Agent not found in this company.
Raw vault
Append-only, versioned retention of complete upstream payloads.
GET/v1/companies/{companyId}/raw
Bulk raw reads are exports and are audited.
200Vault page.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
POST/v1/companies/{companyId}/raw
Append-only and versioned: an unchanged (objectType, objectId, payloadHash) re-sync is skipped; a changed object appends a new version. Payloads land verbatim — re-derivation from history is always possible. 128KB per payload; reference R2 blobs beyond that.
required: source, records
201Vaulted.
400Validation failed; nothing written.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
Integrations
Credentialed connectors (HubSpot, Jobber): connect, sync, revoke.
GET/v1/companies/{companyId}/actors
Every upstream actor (HubSpot owner, Jobber assignee) a sync has seen, with classification status. `pending` actors are scored for NOTHING until classified; `human` actors are never scored.
200The discovery queue.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
POST/v1/companies/{companyId}/actors/{actorId}/classify
kind=agent creates the agent record + source alias (the next idempotent sync ingests the actor's full history). kind=human permanently excludes the actor from scoring — people are never scored. Audited.
required: kind
200Classified.
400Invalid kind.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown actor.
409Actor is already classified.
GET/v1/companies/{companyId}/integrations
200All integrations, ciphertext never included.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
POST/v1/companies/{companyId}/integrations
Live tokens are verified with an upstream ping BEFORE storage, then AES-GCM encrypted at rest — only the last four characters are ever returned again. One active integration per provider per company. Jobber is sandbox-only until its OAuth flow ships. No agent is selected here: syncing DISCOVERS the actors doing the work, and each is classified (AI agent vs human) before anything is scored.
required: provider
201Connected.
400Invalid provider, foreign agent, or invalid_credentials (one generic envelope).
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
409An active integration for this provider already exists.
503integration_encryption_unavailable — encryption key not configured.
DELETE/v1/companies/{companyId}/integrations/{integrationId}
Revocation is permanent for the row; reconnecting creates a new integration. Already-vaulted data is retained.
200Revoked.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown integration.
409Already revoked.
POST/v1/companies/{companyId}/integrations/{integrationId}/sync
Pulls from the provider (live) or fixtures (sandbox), lands every payload in the raw vault FIRST, then derives KPI events per upstream actor. Every actor lands in the discovery queue; ONLY actors classified as AI agents get events ingested — pending actors' events are held (re-sync after classifying ingests the full history), humans' are excluded permanently. Fully idempotent: unchanged upstream data writes nothing. Failures mark the integration `error` and return one generic envelope.
200Sync report.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown integration.
409Integration is revoked.
502upstream_sync_failed.
503integration_encryption_unavailable.
Scoring
Recompute and read scorecards.
GET/v1/companies/{companyId}/agents/{agentId}/scorecard
200Latest score + event count.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown agent.
POST/v1/companies/{companyId}/recompute
Runs the scoring engine (asam model, frozen anchors) over the company's event history. Score records are append-only — every recompute adds a new versioned record; history is never rewritten. Agents below the event floor publish no numeric score (cold start → collecting_data).
200Scored.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
GET/v1/companies/{companyId}/scorecard
Latest ImplementationScore + every agent's latest score, enriched with identity and event counts.
200The scorecard.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
Webhooks
Outbound push: score drops, tier changes, governance caps — HMAC-signed to your endpoint.
GET/v1/companies/{companyId}/webhooks
200All webhooks — secrets never included.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
POST/v1/companies/{companyId}/webhooks
The signing secret (whsec_…) is generated server-side, returned ONCE in this response, and stored encrypted. Verify x-agentscore-signature (HMAC-SHA256 over the exact body) before trusting any delivery. Omitting `events` subscribes to all types.
required: url
201Created — save the secret now.
400Invalid URL or unknown event type.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown company.
503integration_encryption_unavailable.
DELETE/v1/companies/{companyId}/webhooks/{webhookId}
200Disabled.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown webhook.
409Already disabled.
GET/v1/companies/{companyId}/webhooks/{webhookId}/deliveries
Append-only record of every delivery attempt — 'did the webhook fire' is never a mystery.
200Attempts, newest first.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown webhook.
Admin
Key minting and the audit trail. Admin-scoped keys only.
GET/v1/admin/audit
Append-only: who did what, when, to which resource — every auth denial, mutation, connect/revoke, and export. Request-id correlated. No PII.
200Audit rows, newest first.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
GET/v1/admin/companies
200Every company, including soft-deleted.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
GET/v1/admin/keys
200All keys' metadata.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
POST/v1/admin/keys
The plaintext key appears ONCE in this response and is stored only as a SHA-256 hash.
required: name, scopes
201Minted — save the key now.
400Validation failed.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
DELETE/v1/admin/keys/{keyId}
Revocation fails closed: a revoked key is indistinguishable from an unknown one.
200Revoked.
401Missing, malformed, unknown, or revoked API key — one uniform envelope, no oracle.
403Key is valid but lacks the required scope or is bound to a different company.
404Unknown key.
Outbound webhooks
Score drops, tier changes, and governance caps push to your endpoint as HMAC-SHA256-signed JSON — verify the x-agentscore-signature header against your webhook secret before trusting a payload. Every delivery attempt is recorded in an append-only log you can read back; dedupe on the event id.