---
title: Quickstart
description: Get an API key, send your first email, receive inbound mail via webhook, and connect over MCP.
---

# Quickstart

Postfleet is an email API built for autonomous agents. This page takes you from zero to a
sent email, an inbound webhook, and an MCP connection.

Every endpoint lives under the canonical `/api/v1/` prefix and authenticates with a bearer
`pf_` key. See [Authentication](./auth) for the full key model.

## 1. Get an API key

API keys are created and revoked in the dashboard (this is a control-plane action — it is not
exposed over the data-plane API). A key is a bearer secret that starts with `pf_`.

Keys carry a **scope**:

- `bootstrap` — provision-only. Can create mailboxes, nothing else.
- `api` / `mcp` — the working data-plane scopes: send, read, and manage drafts.

Send every request with the key in the `Authorization` header:

```
Authorization: Bearer pf_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
```

## 2. Create a mailbox

A mailbox is an email address your agent owns. Create one with an account-wide key
(mailbox-bound keys cannot create mailboxes):

```bash
curl -X POST https://your-app.example.com/api/v1/mailboxes \
  -H "Authorization: Bearer pf_..." \
  -H "Content-Type: application/json" \
  -d '{"slug": "support"}'
```

Response (`201`):

```json
{ "id": "b1a2...", "address": "agent-support@your-domain.example" }
```

## 3. Send your first email

`POST /api/v1/send` takes exactly one recipient. `mailbox_id` and `text` are required;
`to` is required unless you set `reply_to_message_id`, and `subject` is optional.

```bash
curl -X POST https://your-app.example.com/api/v1/send \
  -H "Authorization: Bearer pf_..." \
  -H "Content-Type: application/json" \
  -d '{
    "mailbox_id": "b1a2...",
    "to": "person@example.com",
    "subject": "Hello from my agent",
    "text": "This email was sent by an autonomous agent."
  }'
```

Success (`201`):

```json
{ "id": "m_123...", "thread_id": "t_456...", "provider_message_id": "prov_789..." }
```

Pass an optional `client_id` to make the send idempotent — a retried request with the same
`client_id` and body replays the stored result instead of sending twice. See
[Sending & idempotency](./sending).

> If the mailbox requires human approval, `POST /api/v1/send` returns `202`
> `{"draft_id": "...", "status": "pending_approval"}` instead of a message id. That is **not**
> a failure and must **not** be retried — the email goes out once a human approves it. See
> [Drafts & human-in-the-loop](./drafts).

## 4. Receive inbound mail via webhook

Configure a webhook URL and signing secret in the dashboard. When mail arrives, Postfleet
POSTs a `message.received` event to your endpoint, signed with a custom HMAC:

- `x-postfleet-signature` — hex `HMAC-SHA256(secret, "{timestamp}.{rawBody}")`
- `x-postfleet-timestamp` — millisecond epoch, part of the signed payload

Verify every event before trusting it, and reject stale timestamps (>5 minutes). Deliveries
are at-least-once, so dedupe on the payload's `event_id`. The full recipe and a copy-pasteable
verification snippet are in [Webhooks](./webhooks).

## 5. Connect over MCP (one-liner)

Point any MCP client at the Postfleet MCP server and pass your key as a bearer header:

```json
{
  "mcpServers": {
    "postfleet": {
      "url": "https://your-app.example.com/api/mcp",
      "headers": { "Authorization": "Bearer pf_..." }
    }
  }
}
```

This exposes tools like `send_email`, `reply_email`, `list_inbox`, `read_email`,
`wait_for_email`, and the draft tools. See [MCP setup](./mcp).

## Where to next

- [Authentication & key scoping](./auth)
- [Sending & idempotency](./sending)
- [Drafts & human-in-the-loop](./drafts)
- [Send lists](./lists)
- [Webhooks](./webhooks)
- [MCP setup](./mcp)
