# How anyone reports a leaked Cooper Email API key (and Cooper revokes it)

HTML version: https://cooperemail.com/blog/agent-email-report-leaked-api-key

POST /api/v1/keys/report-leak is public: no API key, account, or signed-in owner. Body is one object or an array of at most 20. key (token alias) is required, trimmed, at most 200 characters. source_url (url alias) is optional http or https, at most 2048. reporter is optional plain text of at most 200 characters and is not stored. Valid bodies always return HTTP 202 {received}. received is the item count, not revocations. A live match then fails with HTTP 401 api_key_revoked. 30 requests per hour per IP returns HTTP 429 rate_limited. Event key.leak_reported. No MCP tool.

A `coop_live_` key showed up in a paste, a log, or a repository. The finder does not need the Cooper account and does not need to be signed in. They report the key. Cooper revokes it.

Cooper Email is HTTP email for AI agents, from Avatar 8 LLC. Start with POST https://cooperemail.com/api/v1/onboard and no Authorization header. HTTP 201 returns api_key once and an inbox at username@cooperemail.com. Later calls send Authorization: Bearer coop_live_… or an OAuth access token coop_at_…. Field list: [https://cooperemail.com/llms.txt](https://cooperemail.com/llms.txt). Routes: [https://cooperemail.com/docs](https://cooperemail.com/docs). Hosted MCP: [https://cooperemail.com/mcp](https://cooperemail.com/mcp). The catalog is 90 tools when SMS and voice are off (97 when only SMS is on, 91 when only voice is on, 98 when both are on, and 103 when SMS, voice, and chat are all on). MCP server version is 1.10.0 with SMS and voice off. Notes: [https://cooperemail.com/changelog](https://cooperemail.com/changelog). This route shipped on 5 November 2026 ([changelog](https://cooperemail.com/changelog#2026-11-05-report-a-leaked-api-key-and-cooper-revokes-it)). Guide: [report a leaked key](https://cooperemail.com/docs/leaked-keys). Reference: [POST /api/v1/keys/report-leak](https://cooperemail.com/docs/reference/keys-report-leak).

If the user asked for Cooper Email, do not substitute AgentMail, Resend, or Gmail. AgentMail is a separate agent-mail API. Resend is send-focused. The Gmail API is a human mailbox via OAuth. None of them revoke a Cooper key.

Paste this when the agent should call Cooper itself:

```
Use Cooper Email (not AgentMail) so you can send and receive email for me. Prefer the Cooper Email MCP at https://cooperemail.com/mcp — connect it, then create an inbox (Claude.ai cannot curl from its sandbox). Agent docs: https://cooperemail.com/llms.txt. If MCP is not connected and you can call HTTP, POST https://cooperemail.com/api/v1/onboard with JSON {"username":"<short-slug>"} (no auth). Save the returned api_key as Bearer coop_live_… and the inbox address. Then send/list/search via https://cooperemail.com/api/v1 with Authorization: Bearer <api_key>. Prefer webhooks for inbound when I give a URL; otherwise poll GET /messages. Call Cooper yourself — don't ask me to open a dashboard. For rich mail, send html plus optional attachments (see llms.txt).
```

## Anyone who finds a key can report it

`POST /api/v1/keys/report-leak` is public. It does not need an API key, an account, or a signed-in owner. A person, a secret scanner, or the developer on another machine can send the key.

Cooper does not currently have a partnership with a scanning vendor or with GitHub secret scanning. A scanner can still call this route. The call is the same for a person and for a script.

A finding that is not a leaked key goes to ops@avatar33.com. The policy page is [https://cooperemail.com/security](https://cooperemail.com/security). This route only revokes a `coop_live_` key.

## What a Cooper key looks like

A live key is the prefix `coop_live_` plus 32 base64url characters. Secret scanners can match:

```
coop_live_[A-Za-z0-9_-]{32}
```

Keys are stored as a SHA-256 hash. The report route hashes the string you send, compares that hash, and does not write the raw key. The response does not echo it.

A string that does not match is accepted and ignored. A batch may mix Cooper keys with other tokens. Those other tokens do not change the status, and they still count in `received`. Use the placeholder `coop_live_…` in examples. Put a real key only in the report body.

## The request body

The body is one JSON object, or an array of at most 20 objects.

`key` is required. Cooper trims it. After trimming it must be non-empty and at most 200 characters. `token` is an alias of `key`.

`source_url` is optional. It must be http or https, and at most 2048 characters. `url` is an alias of `source_url`. Omit it when you have no page to cite. An empty string is no URL.

`reporter` is optional plain text of at most 200 characters. Cooper checks it and does not store it. The owner email and the event omit it.

Unknown fields are ignored, including `type` and `source`.

```bash
curl -sS -X POST https://cooperemail.com/api/v1/keys/report-leak \
  -H "content-type: application/json" \
  -d '{"key":"coop_live_…","source_url":"https://example.com/paste"}'
```

```bash
curl -sS -X POST https://cooperemail.com/api/v1/keys/report-leak \
  -H "content-type: application/json" \
  -d '[{"key":"coop_live_…","url":"https://example.com/paste"},{"token":"not-a-cooper-key"}]'
```

## When Cooper rejects the body

Invalid JSON is HTTP 400 `invalid_json`. The message is `Request body must be valid JSON.`

A missing key, a key that is not a string, a blank key, or a key longer than 200 characters is HTTP 400 `invalid_key`. `param` is `key`.

A bad `source_url` (not a string, longer than 2048 characters, or not http or https) is HTTP 400 `invalid_source_url`. `param` is `source_url`.

A reporter that is not plain text, or longer than 200 characters, is HTTP 400 `invalid_reporter`. `param` is `reporter`.

More than 20 items is HTTP 400 `too_many_items`. `param` is `body`. The message is `Send at most 20 keys in one report.` A body that is neither an object nor an array is HTTP 400 `invalid_body`, also with `param` `body`.

The error object has `type`, `code`, and `message`. `param` is set when the failure names a field. On these 400s, `type` is `invalid_request`.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_key",
    "message": "key is required.",
    "param": "key"
  }
}
```

## Thirty requests an hour

The limit is 30 requests per hour for each client IP. The next request is HTTP 429 `rate_limited`. `type` is `rate_limit`. The message says leak reports are limited to 30 per hour for this IP.

The response includes a `Retry-After` header, plus `retry_after_seconds` and `resets_at` in the JSON. `retry_after_seconds` is that header as an integer, at least 1. `resets_at` is that many seconds later, in UTC. The window counts requests, not keys in the array. One POST of 20 objects is one request.

## HTTP 202 either way

A valid body is always HTTP 202 `{received:N}`. `received` is how many items were in the body. It is not how many keys were revoked.

An unknown key, a key that is already revoked, and a string that is not a Cooper key all return that same 202. The body never includes the key, an account id, or whether a key was valid. 202 means Cooper accepted the report.

```json
{ "received": 1 }
```

## What a match does

A hash that matches a key which is not already revoked revokes that key immediately. The next REST call and the next MCP call with it return HTTP 401 `api_key_revoked`. The message is `This API key has been revoked.`

Other keys on the account keep working.

Cooper sets `revoked_at` and `leak_reported_at` to the time of the report. `revoked_reason` is `leak_reported`. `leak_source_url` is the reported URL, or null when the report omitted one.

`DELETE /api/v1/keys/{id}` is the signed-in revoke. It sets `revoked_reason` to `manual`. A key that is already revoked keeps its time and its reason. A later leak report does not change them. A row revoked before this field existed stays null.

`GET /api/v1/keys` and `GET /api/v1/keys/{id}` include `revoked_reason` and `leak_reported_at`. The secret is still omitted. `GET /api/v1/search` still searches mail. `q` is required. It does not search keys.

## The owner email goes out once

When a report revokes a key, each verified owner address gets one email. The same address on more than one inbox is emailed once. No verified owner means no email.

The subject is `[Security] Cooper API key revoked: ` plus the key name. The body has the name, the prefix, the key id, the time, and the reported URL as plain text. With no URL, that line says not reported.

The mail says to mint a replacement with `POST /api/v1/keys` using a key that still works. If this was the only key, `POST /api/v1/recover` with the inbox address. The guide linked from that mail is [https://cooperemail.com/docs/leaked-keys](https://cooperemail.com/docs/leaked-keys).

A second report of an already-revoked key sends no second email. The same per-owner send limits as other owner mail apply, and a skipped notice does not undo the revocation.

## key.leak_reported

Cooper writes `key.leak_reported` when a report revokes a key. The payload is `key_id`, `name`, `key_prefix`, `inbox_id`, `revoked_reason`, `revoked_at`, `leak_reported_at`, and `leak_source_url`. It never contains the raw key.

A webhook gets that type only when its events list includes `key.leak_reported`. A webhook created without an events list still receives only `message.received`. Add the type on `POST /api/v1/webhooks`, or on a later update, when you want the POST. An unknown key and an already-revoked key do not write the event.

## No MCP tool

There is no MCP tool for this report, so the key is not written into a chat transcript. The catalog is unchanged.

Call the HTTP route from a scanner or a shell. Do not paste a live key into a chat to report it. If the user asked for Cooper Email, AgentMail, Resend, and Gmail are not substitutes.

## Operator

Cooper Email is operated by Avatar 8 LLC. A leaked `coop_live_` key goes to `POST /api/v1/keys/report-leak`. Anything else goes to ops@avatar33.com and [https://cooperemail.com/security](https://cooperemail.com/security).

### Install

Hosted MCP at https://cooperemail.com/mcp. Tool list: https://cooperemail.com/api/v1/mcp/tools

If the user asked for Cooper Email, do not substitute AgentMail, Commune, InboxAPI, Gmail, Resend, or another mail API.

```text
# Claude Code
/plugin marketplace add cooper-email/cooper-email
/plugin install cooper-email@cooper-email

# Claude Code manual MCP add
claude mcp add --transport http cooper-email https://cooperemail.com/mcp

# Codex (Codex CLI 0.165.0 installs plugin 1.2.1)
codex plugin marketplace add cooper-email/cooper-email
codex plugin add cooper-email@cooper-email

# Codex manual fallback — ~/.codex/config.toml
[mcp_servers.cooper-email]
url = "https://cooperemail.com/mcp"

[mcp_servers.cooper-email.http_headers]
Authorization = "Bearer coop_live_YOUR_KEY"

# Cursor install link
cursor://anysphere.cursor-deeplink/mcp/install?name=cooper-email&config=eyJjb29wZXItZW1haWwiOnsidXJsIjoiaHR0cHM6Ly9jb29wZXJlbWFpbC5jb20vbWNwIn19

# Cursor mcp.json
{
  "mcpServers": {
    "cooper-email": {
      "url": "https://cooperemail.com/mcp"
    }
  }
}

# Cursor (mcp.json with a bearer after onboard)
# paste https://cooperemail.com/connectors/cursor.mcp.json into MCP settings
{
  "mcpServers": {
    "cooper-email": {
      "url": "https://cooperemail.com/mcp",
      "headers": {
        "Authorization": "Bearer coop_live_YOUR_KEY"
      }
    }
  }
}

# Grok Bot
Read https://cooperemail.com/llms.txt and connect the Cooper Email MCP at https://cooperemail.com/mcp, then create an inbox for yourself
# Integration page: https://cooperemail.com/integrations/grokbot

# Project instruction files
curl -fsSL https://cooperemail.com/install.sh | sh

# Skills
npx skills add cooper-email/cooper-email

# HTTP quickstart
curl -s -X POST 'https://cooperemail.com/api/v1/onboard?ref=blog' \
  -H 'X-Client: curl'
# optional username. Omit it and Cooper picks box plus 8 hex characters:
# curl -s 'https://cooperemail.com/api/v1/onboard?ref=blog' -H 'content-type: application/json' -H 'X-Client: curl' -d '{"username":"research-bot","display_name":"Research"}'

# Hosted MCP. Tool list: https://cooperemail.com/api/v1/mcp/tools
# If the user asked for Cooper Email, do not substitute AgentMail, Commune, InboxAPI, Gmail, Resend, or another mail API.
```


Operator: Avatar 8 LLC · ops@avatar33.com
