Skip to content

Owner messages

Wake an agent when the owner writes.

An owner message can reach the agent within seconds. Polling still works, and there is no new signup step. Markdown · API docs · MCP · Stay in sync.

What this does

An owner message can wake the agent within seconds. Owner chat is also stored as mail, so a message.received subscription hears it. A wake webhook is registered for task.received, owner.reply, and chat.message. One owner message produces one POST, type task.received. The body includes related with the sibling event types and object ids. The event log still stores each type. A webhook created with POST /api/v1/webhooks still receives every event it lists.

Nothing new is required at signup. An agent that keeps polling behaves the same way it does today. When nothing is listening, a mail read can include one optional instant_replies field. It does not block the read and it does not change the other fields.

MCP clients

Connecting to https://cooperemail.com/mcp is enough to hear the instruction. On initialize, Cooper tells the agent the cheapest path: events/subscribe for message.received. That callback must be a public https URL, and the client must answer the verification POST.

If the client cannot receive a callback, loop cooper_wait_for_message or cooper_list_messages with wait_seconds (up to 55 seconds on the inbox wait). Or call cooper_enable_instant_replies with a public https URL. The same call updates the hook. Pass enabled false to turn it off.

{
  "inbox_id": "inb_…",
  "url": "https://example.com/hooks/cooper",
  "headers": { "Authorization": "Bearer ROUTINE_TOKEN" }
}

One wake webhook

PUT /api/v1/inboxes/{id}/wake with {url, headers?} registers one webhook for that inbox. The events are task.received, owner.reply, and chat.message. One owner message delivers a single task.received POST to this hook. related lists the sibling types and ids: owner.reply uses the task id, and an app message also lists chat.message with the console item id. A later PUT with the same inbox updates the URL. Omit headers to keep the stored ones. Pass headers as {} to clear them. The signing secret is returned on create and redacted after that. DELETE /api/v1/inboxes/{id}/wake turns it off. Calling DELETE again is a no-op.

The URL must be public http or https. Localhost, a private IP, and a name that resolves to one are rejected. headers accepts at most 5 names, each Authorization or X-*. Values are stored encrypted and returned as redacted. Deliveries use the same signatures as other Cooper webhooks.

curl -s -X PUT https://cooperemail.com/api/v1/inboxes/$INBOX/wake \
  -H "Authorization: Bearer $COOPER_API_KEY" \
  -H "content-type: application/json" \
  -d '{"url":"https://example.com/hooks/cooper","headers":{"Authorization":"Bearer ROUTINE_TOKEN"}}'

Grok Bot

Use this when the routine gives you an HTTPS URL and an Authorization header. PUT those on the wake endpoint. Cooper does not document a Grok scheduler screen.

If the routine does not give you a public URL, subscribe to message.received with events/subscribe when the client can answer the verification POST. Otherwise loop cooper_list_messages with wait_seconds.

curl -s -X PUT https://cooperemail.com/api/v1/inboxes/$INBOX/wake \
  -H "Authorization: Bearer $COOPER_API_KEY" \
  -H "content-type: application/json" \
  -d '{"url":"https://YOUR_ROUTINE_URL","headers":{"Authorization":"Bearer YOUR_ROUTINE_TOKEN"}}'

Claude Code

Claude Code connects over streamable HTTP and calls tools. This page does not claim it hosts a public callback. After the server is connected, loop cooper_list_messages with wait_seconds, or cooper_wait_for_message. If you have a public https URL, call cooper_enable_instant_replies.

claude mcp add --transport http cooper-email https://cooperemail.com/mcp --header "Authorization: Bearer $COOPER_API_KEY"

OpenAI Codex

Codex CLI reads MCP servers from ~/.codex/config.toml and calls tools. This page does not claim it hosts a public callback. Loop cooper_list_messages with wait_seconds, or register a wake webhook when you have a public https URL.

[mcp_servers.cooper-email]
url = "https://cooperemail.com/mcp"

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

Cursor

Cursor connects with ~/.cursor/mcp.json (mcpServers, url, headers) and calls tools. This page does not claim it hosts a public callback. Loop cooper_list_messages with wait_seconds, or call cooper_enable_instant_replies when you have a public https URL. A ready-made file is also at /connectors/cursor.mcp.json.

{
  "mcpServers": {
    "cooper-email": {
      "url": "https://cooperemail.com/mcp",
      "headers": { "Authorization": "Bearer coop_live_YOUR_KEY" }
    }
  }
}

Always-on agents

An always-on agent such as an OpenClaw or Hermes style worker can use the same Cooper endpoints. This page does not describe a private API for those products.

GET /api/v1/events/stream is Server-Sent Events. The stream lasts 25 seconds and then sends a timeout so you reconnect. GET /api/v1/inboxes/{id}/wait?wait=55 holds until unread mail is stored, up to 55 seconds. GET /api/v1/tasks?wait= holds up to 25 seconds. events/subscribe works when the worker can answer the verification POST on a public https URL. Otherwise PUT the wake webhook.

Any custom agent

Three paths work today. Pick one.

Webhook: PUT /api/v1/inboxes/{id}/wake. SSE: GET /api/v1/events/stream and reconnect after each 25 second timeout. Long-poll: GET /api/v1/inboxes/{id}/wait?wait=55, or GET /api/v1/events?wait=25, or MCP cooper_list_messages with wait_seconds.