# Fund Census auth.md

How AI agents, and the programs they run, can authenticate to Fund Census. Fund Census serves public SEC filing data and is read-only: every credential below grants read access only.

## Choose a method

- **No credentials:** the JSON API under https://fundcensus.com/api works without signing in. Requests are limited per IP address, and lists stop at the first 500 rows.
- **Agent registration:** an agent registers on its own, then a person claims it. Follow the steps below. This is the method for agents that have no user identity.
- **API key:** a person signs in at https://fundcensus.com/account and creates a key. Send it as `Authorization: Bearer <key>` on API requests. Keys share the account's daily allowance.
- **MCP with OAuth:** MCP clients connect to https://fundcensus.com/mcp and send a person through sign-in. See [OAuth for MCP clients](#oauth-for-mcp-clients).

## Scopes

| Scope | Grants |
| --- | --- |
| `api.read` | The JSON API under https://fundcensus.com/api |
| `mcp.read` | The MCP server at https://fundcensus.com/mcp |

An unclaimed agent gets `api.read` at the anonymous tier: the same per-IP limits and 500-row lists as a request without credentials. MCP answers it with 403 `insufficient_scope`. A claimed agent gets `api.read mcp.read`, and its requests count toward the daily allowance of the person who claimed it.

## Step 1: Discover

- Protected resource metadata: https://fundcensus.com/.well-known/oauth-protected-resource (resource `https://fundcensus.com`) and https://fundcensus.com/.well-known/oauth-protected-resource/mcp (resource `https://fundcensus.com/mcp`).
- Authorization server metadata: https://fundcensus.com/.well-known/oauth-authorization-server. Its `agent_auth` block names the registration endpoint (`identity_endpoint`, also published as `register_uri`) and the claim endpoint (`claim_endpoint`, also `claim_uri`). The only identity type is `anonymous`.

## Step 2: Register

```http
POST https://fundcensus.com/agent/identity
Content-Type: application/json

{ "type": "anonymous" }
```

Response:

```json
{
  "registration_id": "reg_...",
  "registration_type": "anonymous",
  "identity_assertion": "<JWT>",
  "assertion_expires": "2026-10-17T12:00:00.000Z",
  "pre_claim_scopes": ["api.read"],
  "claim_url": "https://fundcensus.com/agent/identity/claim",
  "claim_token": "clm_...",
  "claim_token_expires": "2026-10-17T12:00:00.000Z",
  "post_claim_scopes": ["api.read", "mcp.read"]
}
```

Keep `claim_token` in memory; it is shown once. The registration lasts 24 hours unless a person claims it. `service_auth` answers `service_auth_not_enabled` and `identity_assertion` answers `issuer_not_enabled`.

## Step 3: Exchange the assertion for an access token

```http
POST https://fundcensus.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&assertion=<identity_assertion>
```

The response is a standard token response: `access_token` (starts with `fca_`), `token_type` `Bearer`, `expires_in` `3600` and `scope`. There is no refresh token: exchange the assertion again when the access token expires. `resource` is optional; if you send it, use `https://fundcensus.com` or `https://fundcensus.com/mcp`. One token works on both.

## Step 4: Ask a person to claim the agent

Start a claim with the email address of the person you act for. Only someone signed in to Fund Census with that address can confirm.

```http
POST https://fundcensus.com/agent/identity/claim
Content-Type: application/json

{ "claim_token": "clm_...", "email": "person@example.com" }
```

Response:

```json
{
  "registration_id": "reg_...",
  "claim_attempt_id": "cla_...",
  "status": "initiated",
  "expires_at": "2026-10-16T12:10:00.000Z",
  "claim_attempt": { "user_code": "123456", "expires_in": 600, "verification_uri": "https://fundcensus.com/agent/claim?attempt=...", "interval": 10 }
}
```

Give the person both in one message, for example: "Open this link, sign in to Fund Census with Google or GitHub, and enter this 6-digit code: 123456." The code goes into the page they open, not back to you. Starting a new claim replaces the previous link and code.

Then poll every `interval` seconds:

```http
POST https://fundcensus.com/oauth/token
Content-Type: application/x-www-form-urlencoded

grant_type=urn:workos:agent-auth:grant-type:claim&claim_token=<claim_token>
```

- `authorization_pending`: the person hasn't confirmed yet. Keep polling.
- `slow_down`: wait longer between polls.
- `expired_token`: the code expired or was mistyped 5 times. Start a new claim with the same `claim_token`. If that answers `claim_expired` or `invalid_claim_token`, register again.
- Success: a token response with the claimed scope, plus a new `identity_assertion` and `assertion_expires`. This answer comes once; the claim token stops working after it.

Claiming makes the earlier assertion and access tokens stop working. Use the new ones. The new assertion lasts 30 days.

## Step 5: Call the API or MCP server

Send `Authorization: Bearer <access_token>` to https://fundcensus.com/api (see https://fundcensus.com/openapi.json) or to the MCP server at https://fundcensus.com/mcp over streamable HTTP.

When the access token expires, repeat Step 3 with the current assertion. If Step 3 answers `invalid_grant`, the assertion expired or was revoked: register again.

## Revocation

- **You:** `POST https://fundcensus.com/oauth/token` with form fields `token=<access_token or identity_assertion>`. This revokes the whole registration: every token and assertion for it stops working. The answer is 200 even for unknown tokens.
- **The person:** their account page lists the agents they claimed and can revoke any of them. Deleting their account revokes all of them.

## Errors

| Code | Where | What to do |
| --- | --- | --- |
| `invalid_request` | `/agent/identity`, `/agent/identity/claim` | Fix the JSON body. |
| `invalid_claim_token` | `/agent/identity/claim` | The claim token is unknown or used. Register again. |
| `claimed_or_in_flight` | `/agent/identity/claim` | The agent is already claimed. Poll the token endpoint or use your tokens. |
| `claim_expired` (410) | `/agent/identity/claim` | Register again. |
| `invalid_grant` | `/oauth/token` | The assertion is invalid, expired, revoked or superseded. Register again. |
| `invalid_target` | `/oauth/token` | Use one of the two resources above, or leave `resource` out. |
| `rate_limited` (429) | any | Wait a minute and retry. |

## OAuth for MCP clients

- Clients register dynamically at https://fundcensus.com/oauth/register, or use a Client ID Metadata Document URL as their client_id.
- The grant is an authorization code with PKCE (S256), followed by refresh tokens. Access tokens last one hour.
- Set the `resource` parameter to https://fundcensus.com/mcp. The person signs in with Google or GitHub and approves the connection.

## Limits

Registration and claim starts are limited to 10 a minute per IP address. Token requests and claim polls share the anonymous per-IP limit. A person can claim up to 10 agents. Data-tool calls and API requests from claimed agents and keys count toward a daily allowance that resets at midnight UTC. Requests over a limit are refused with a message that explains it. Terms: https://fundcensus.com/terms. Privacy: https://fundcensus.com/privacy.
