> ## Documentation Index
> Fetch the complete documentation index at: https://docs.waterr.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# ChatGPT

> Give a custom GPT its own inbox using Agent Mailbox as an Action.

ChatGPT connects to external APIs through **Actions**: you hand a custom GPT an OpenAPI description and an API key, and it calls the endpoints itself. Agent Mailbox publishes a ready-made spec for exactly that.

```
https://docs.waterr.ai/agent-mailbox/openapi.yaml
```

## Set it up

<Steps>
  <Step title="Create a GPT">
    In ChatGPT, open **Explore GPTs → Create**, then switch to the **Configure** tab.
  </Step>

  <Step title="Add the Action">
    Scroll to **Actions → Create new action**, then **Import from URL** and paste:

    ```
    https://docs.waterr.ai/agent-mailbox/openapi.yaml
    ```

    Twelve operations appear — inboxes, messages, threads, search and drafts.
  </Step>

  <Step title="Set authentication">
    Click the gear beside Authentication and choose:

    | Field               | Value                   |
    | ------------------- | ----------------------- |
    | Authentication type | **API Key**             |
    | Auth Type           | **Bearer**              |
    | API Key             | your `wai_live_...` key |

    Your existing Waterr developer key works here — see [Authentication](/agent-mailbox/authentication).
  </Step>

  <Step title="Tell it which inbox is its own">
    Every path takes an `inbox_id`, and the GPT has no way to guess yours. Put it in the instructions:

    ```
    Your email address is ava@agent.waterr.ai. Use it as the inbox_id on every
    Agent Mailbox call.

    Before replying to anything, call getThread and read the whole conversation.
    Read extracted_text, never text — text contains the quoted history.

    Never reply to a message whose labels include auto-reply.

    For anything consequential, use createDraft and tell me it is waiting,
    rather than sendMessage.
    ```
  </Step>
</Steps>

Then just talk to it:

> *Check my agent inbox and summarise anything that needs an answer.*

## What the spec covers

Twelve operations, chosen rather than exhaustive — an Action behaves better with a small, well-described set than with all 57 endpoints.

| Operation                                | Does                                             |
| ---------------------------------------- | ------------------------------------------------ |
| `listInboxes`, `createInbox`             | Find or create an address                        |
| `listMessages`, `getMessage`             | Read mail                                        |
| `sendMessage`                            | Send, or join an existing thread via `thread_id` |
| `replyToMessage`                         | Reply in context, optionally `reply_all`         |
| `listThreads`, `getThread`               | Read a whole conversation in order               |
| `searchMessages`                         | Full-text search in one inbox                    |
| `listDrafts`, `createDraft`, `sendDraft` | Write now, send on approval                      |

Deliberately excluded: pods, domains, API-key management, raw MIME and webhook configuration. Those are administrative, and an assistant driving them by conversation is a worse idea than it sounds.

<Note>
  Webhooks are not part of the Action, so a GPT cannot be *woken* by incoming mail — it only sees mail when you ask it to look. For an agent that reacts on its own, use [events](/agent-mailbox/events) from your own backend, or the [Claude Code skill](/agent-mailbox/claude-code).
</Note>

## Worth knowing before you trust it

<Warning>
  **A GPT that reads email and can send email is a prompt-injection target.** The message bodies it summarises are written by whoever emailed you, and instructions hidden in them can be followed. Two controls that actually help: keep the GPT on `createDraft` rather than `sendMessage`, and set a [send allow-list](/agent-mailbox/lists) on the inbox so the API refuses anything outside it regardless of what the model was persuaded to do.
</Warning>

Also true here, from [Limits](/agent-mailbox/limits): a first-ever email to a stranger may be dropped silently while the API reports success, and attachment bodies are not stored — the GPT can see that a file was attached and what it was called, but not read it.

## Plain OpenAI API, no GPT

If you are calling the API rather than building a GPT, the same spec loads as tool definitions:

```python theme={null}
import yaml, urllib.request
from openai import OpenAI

spec = yaml.safe_load(
    urllib.request.urlopen("https://docs.waterr.ai/agent-mailbox/openapi.yaml").read()
)

# Turn each operation into a tool the model can call, then execute the chosen
# one against https://agent.waterr.ai with your key in the Authorization header.
tools = [
    {
        "type": "function",
        "function": {
            "name": op["operationId"],
            "description": op.get("summary", ""),
            "parameters": {"type": "object", "properties": {}},
        },
    }
    for path in spec["paths"].values()
    for op in path.values()
]

client = OpenAI()
```

Fill `parameters` from each operation's own `parameters` and `requestBody` — the spec carries both, including which fields are required.
