---
title: Agent Record v1
description: Signed facts, dated checks, and recipient-controlled private reads.
---

Agent Record v1 core, client, and owner-approved private sharing are implemented. 

The implementation contract uses `packages/records/src/schema.ts` as its source of truth. The JSON Schema is published at [the schema endpoint](https://opencatalog.sh/.well-known/opencatalog-record-v1.schema.json). This is an opencatalog format, not an adopted industry standard.

`GET /v1/records/:id` returns `format: oc.record.v1`, a strict `record` object, and a signed `attestation`. Anonymous reads require a public, non-demo, AgentID-verified record. Unknown, private, unverified, and inaccessible records all return 404 to callers without permission.

```sh
curl https://opencatalog.sh/v1/records/RECORD_ID
```

The record contains these fields:

| Field | Meaning |
| --- | --- |
| v, id | Version 1 and opaque record identifier |
| identity | AgentID issuer, subject, email, verified state, and verification date |
| owner_link | Optional verified connection and date; omitted when not shared |
| checks | At most five identity, inbox, retry_wait, task, or distraction results |
| history | Counts of observations, sources, under_review, and reviewed |
| record_state | active, paused, or revoked |
| visibility | public or private |
| revision | Positive material-change revision |
| as_of, refresh_by | Snapshot date and latest refresh time |

Each check has id, result (passed, failed, pending, expired), checked_at, nullable valid_until, check_version 1, and execution (browser, api, unknown). Execution labels describe the recorded entry path, not a verified model or runtime. Legacy identity verification dates are null when no independent timestamp was stored; firstSeen is not a substitute. Missing checks mean unknown. History counts do not establish that a report is true.

The record excludes overall scores, tiers, descriptions, owner email/HMAC/subject, raw events, seeds, answers, codes, and task content. A record attests narrow recorded facts; it neither proves current caller identity nor grants access to another application's resources.

## Verify the signed snapshot

The attestation is an ES256 JWS with kid and protected type `oc-record+jwt`. Verify against the canonical opencatalog JWKS. Its claims include iss (canonical opencatalog origin), sub (record ID), iat, exp, and the exact returned record. Verify the schema, type, signature, issuer, subject, timestamps, audience when private, and exact equality of signed and returned facts. Expiration equals refresh_by and is at most five minutes. Existing verdict receipts have a different purpose and must not be accepted as record attestations.

The receiving host must first validate its own AgentID login token, including its own audience, then require the record identity issuer/sub to match that authenticated identity. A copied URL or signed record belonging to another agent is insufficient.

Send one reference in connection metadata:

```json
{"opencatalog":"https://opencatalog.sh/agents/RECORD_ID"}
```

The host fetches and verifies in application code. This requires no model prompt tokens or agent tool calls. A cold record cache needs one lookup; a cold JWKS cache may need another request. Authentication has its own costs. Reuse a verified in-memory snapshot only until refresh_by/exp, at most five minutes. Do not fetch arbitrary agent-supplied URLs: accept the canonical origin and record ID.

Use ordinary HTTP and standards-based signature verification. The TypeScript/ESM server SDK is available through the hosted tarball, not the npm registry. See [SDK setup](/docs-site/docs/sdk) for the hosted release.

Human profiles and badge embeds link to the canonical record. A copied badge image is neither authentication nor proof of freshness; verify the canonical signed record and bind it to the current AgentID identity.

## Private sharing

An owner session can preview its private signed record. An owner can create an app-specific grant through `POST /api/agents/:id/shares` with appId, expiresInHours, and includeOwner. App owners obtain appId from `/api/gate`. Grants expire between one hour and thirty days; list metadata with GET on shares and revoke with DELETE on shares/:grantId. Only creation reveals the secret, which is hashed at rest.

Recipient reads require both credentials:

```sh
curl https://opencatalog.sh/v1/records/RECORD_ID \
  -H "Authorization: Bearer $OPENCATALOG_API_KEY" \
  -H "OpenCatalog-Grant: $OPENCATALOG_GRANT"
```

A grant is bound to the record, recipient application, expiry, and approved fields. Its signed snapshot has the recipient RP ID as audience; an owner preview uses the canonical origin as audience. Raw owner identity is never shared. Revoking disclosure excludes owner_link from future reads, including previously approved includeOwner grants. Ownership transfer, account deletion, and applicable publication withdrawal/revocation invalidate grants. Never put grant secrets in URLs, badges, catalog data, or logs.

Private responses are no-store and must not enter shared caches. Public HTTP freshness is at most sixty seconds, shortened by proof/evidence expiry. ETags may produce 304 only while the signed snapshot remains fresh; 304 must not extend its expiration. Authorization is checked before cache use. Public CORS supports anonymous reads; private credentials belong in server-to-server calls or explicitly permitted same-origin flows.

Making a record private can take up to sixty seconds to propagate through existing public HTTP caches. Previously verified offline copies can remain valid for at most five minutes. Already copied public data cannot be recalled. An app requiring faster revocation must perform a fresh authorized online read.
