# Shipmail Markdown API Reference

Shipmail is an API-first email provider for custom-domain mailboxes, outbound sending, inbound processing, webhooks, and human-accessible IMAP/JMAP mail.

Use this file when a markdown reference is easier than the HTML docs. For exact schemas, generate clients from the OpenAPI spec at `https://shipmail.to/openapi.json`.

## Canonical URLs

- App: `https://shipmail.to`
- API base: `https://shipmail.to/api/v1`
- HTML docs: `https://shipmail.to/docs`
- Markdown docs: `https://shipmail.to/docs.md`
- LLM summary: `https://shipmail.to/llms.txt`
- Agent quick start: `https://shipmail.to/skill.md`
- OpenAPI: `https://shipmail.to/openapi.json`
- CLI docs: `https://shipmail.to/docs/cli`
- MCP docs: `https://shipmail.to/docs/mcp`

## Authentication

All endpoints except `GET /status` require a bearer token.

```text
Authorization: Bearer sm_live_...
```

API key scopes:

- `domains:read`, `domains:write`
- `mailboxes:read`, `mailboxes:write`
- `messages:read`, `messages:write`
- `threads:read`
- `webhooks:read`, `webhooks:write`
- `suppressions:read`, `suppressions:write`

## Rate Limits

- `read`: 1000 requests/minute
- `write`: 200 requests/minute
- `send`: 100 requests/minute
- `verification`: 1 request/minute

Responses include `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`.

## Pagination

Most list endpoints use cursor pagination with `cursor` and `limit`. Responses include:

```json
{
  "pagination": {
    "next_cursor": null,
    "has_more": false,
    "limit": 25
  }
}
```

Mailbox inbox message listing uses JMAP position pagination with `position`, `limit`, `total`, `has_more`, and `next_position`.

## Errors

All API errors use:

```json
{
  "error": {
    "type": "validation_error",
    "message": "Human-readable message",
    "request_id": "req_..."
  }
}
```

Common types: `validation_error`, `authentication_error`, `authorization_error`, `quota_exceeded`, `not_found`, `rate_limit_error`, `conflict`, `internal_error`.

## Core Agent Workflow

1. Create or register a domain.
2. Verify DNS records.
3. Create a mailbox.
4. Send with `POST /messages`.
5. Read inbound mail with `GET /mailboxes/{id}/inbox/messages` or receive `message.received` webhooks.
6. Reply with `POST /messages/{id}/reply` or `POST /threads/{id}/reply`.
7. Move, mark, star, or delete inbox messages with mailbox inbox action endpoints.

## Endpoint Inventory

### Status

- `GET /status` returns API health, version, time, and request ID. No auth required.

### Domains

- `POST /domains` creates a domain. Body: `{ name }`.
- `GET /domains` lists domains. Query: `cursor?`, `limit?`.
- `GET /domains/{id}` fetches one domain.
- `PATCH /domains/{id}` updates catch-all routing. Body: `{ catch_all_mailbox_id }`.
- `DELETE /domains/{id}` deletes a domain.
- `POST /domains/{id}/verification` checks DNS and outbound verification.
- `POST /domains/search` searches purchasable domains. Body: `{ keyword }`.
- `POST /domains/register` registers a domain through Shipmail. Requires active subscription and charges the saved payment method.

### Mailboxes

- `POST /mailboxes` creates a mailbox. Body: `{ domain_id, address, display_name? }`.
- `GET /mailboxes` lists mailboxes. Query: `domain_id?`, `cursor?`, `limit?`.
- `GET /mailboxes/{id}` fetches one mailbox.
- `PATCH /mailboxes/{id}` updates display name. Body: `{ display_name }`.
- `DELETE /mailboxes/{id}` deletes a mailbox.
- `PATCH /mailboxes/{id}/password` resets the mailbox login password. Body: `{ password }`.
- `PATCH /mailboxes/{id}/auto-reply` configures vacation/auto-reply. Body: `{ enabled, subject?, body?, from_date?, to_date? }`.
- `PATCH /mailboxes/{id}/spam-filter` sets spam threshold. Body: `{ threshold }`, integer `1` through `14`.

### Mailbox Folders, Identities, And Rules

- `GET /mailboxes/{id}/folders` lists system and custom folders.
- `POST /mailboxes/{id}/folders` creates a custom folder. Body: `{ name }`.
- `PATCH /mailboxes/{id}/folders/{folder_id}` renames a custom folder. Body: `{ name }`.
- `DELETE /mailboxes/{id}/folders/{folder_id}` deletes a custom folder after moving its messages to Trash.
- `GET /mailboxes/{id}/identities` lists JMAP sending identities.
- `GET /mailboxes/{id}/rules` gets server-side inbox rules and available target folders.
- `PUT /mailboxes/{id}/rules` replaces inbox rules. Body: `{ rules }`.

### Mailbox Inbox

- `GET /mailboxes/{id}/inbox/messages` lists inbound JMAP messages. Query: `folder_id?`, `folder_role?`, `search_text?`, `position?`, `limit?`, `has_keyword?`, `not_keyword?`.
- `PATCH /mailboxes/{id}/inbox/messages/{message_id}` sets read/starred state. Body: `{ read?, starred? }`.
- `POST /mailboxes/{id}/inbox/messages/{message_id}/move` moves one message. Body: `{ from_folder_id?, target_role? | target_folder_id? }`.
- `DELETE /mailboxes/{id}/inbox/messages/{message_id}` permanently deletes a message already in Trash or Junk.
- `GET /mailboxes/{id}/inbox/threads/{thread_id}` gets full inbound thread messages, body parts, and attachment metadata.
- `GET /mailboxes/{id}/inbox/attachments?blob_id=...&name=...` downloads raw attachment bytes.

System inbox folder roles: `inbox`, `starred`, `sent`, `drafts`, `archive`, `junk`, `trash`.

Action target roles: `inbox`, `archive`, `junk`, `trash`.

JMAP keywords: `$flagged`, `$seen`, `$draft`, `$answered`, `$forwarded`.

### Messages

- `POST /messages` sends an email. Body: `{ mailbox_id?, from?, to, cc?, bcc?, reply_to?, subject, html?, text?, in_reply_to?, references?, attachments? }`.
- `GET /messages` lists stored messages. Query: `mailbox_id`, `cursor?`, `limit?`.
- `GET /messages/{id}` fetches one stored message.
- `POST /messages/{id}/reply` replies to a specific message. Body: `{ to, cc?, html?, text? }`.

Recipient input can be an email string, a display-name string such as `Jane Doe <jane@example.com>`, or `{ address, name? }`.

### Threads

- `GET /threads` lists thread summaries. Query: `mailbox_id`, `cursor?`, `limit?`.
- `GET /threads/{id}` gets messages in a thread. Query: `cursor?`, `limit?`.
- `POST /threads/{id}/reply` replies to a thread. Body: `{ to?, cc?, html?, text? }`.

### Webhooks

- `POST /webhooks` creates a webhook. Body: `{ url, events, description? }`.
- `GET /webhooks` lists webhooks. Query: `cursor?`, `limit?`.
- `GET /webhooks/{id}` fetches one webhook.
- `PATCH /webhooks/{id}` updates a webhook. Body: `{ url?, events?, description?, active? }`.
- `DELETE /webhooks/{id}` deletes a webhook.
- `POST /webhooks/{id}/rotate-secret` rotates the signing secret.
- `POST /webhooks/{id}/test` sends a `webhook.test` event.
- `GET /webhooks/{id}/deliveries` lists delivery attempts. Query: `status?`, `event_type?`, `cursor?`, `limit?`.

Webhook event types:

- `message.received`
- `message.sent`
- `message.delivered`
- `message.bounced`
- `message.complained`
- `domain.verified`
- `domain.verification_failed`
- `domain.degraded`
- `org.reputation_warning`
- `org.sending_throttled`
- `org.sending_suspended`
- `org.reputation_recovered`

### Suppressions

- `GET /suppressions` lists suppressed addresses.
- `DELETE /suppressions/{email}` removes one suppression.

## Common Examples

### Create Domain And Mailbox

```bash
curl -X POST https://shipmail.to/api/v1/domains \
  -H "Authorization: Bearer $SHIPMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name":"example.com"}'

curl -X POST https://shipmail.to/api/v1/mailboxes \
  -H "Authorization: Bearer $SHIPMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"domain_id":"dom_abc123","address":"agent","display_name":"Ops Agent"}'
```

### Send And Read Replies

```bash
curl -X POST https://shipmail.to/api/v1/messages \
  -H "Authorization: Bearer $SHIPMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "mailbox_id":"mbx_abc123",
    "to":["user@example.com"],
    "subject":"Hello",
    "text":"Hi there",
    "html":"<p>Hi there</p>"
  }'

curl "https://shipmail.to/api/v1/mailboxes/mbx_abc123/inbox/messages?folder_role=inbox&limit=25" \
  -H "Authorization: Bearer $SHIPMAIL_API_KEY"
```

### Move And Mark Inbox Mail

```bash
curl -X PATCH https://shipmail.to/api/v1/mailboxes/mbx_abc123/inbox/messages/eml_123 \
  -H "Authorization: Bearer $SHIPMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"read":true,"starred":false}'

curl -X POST https://shipmail.to/api/v1/mailboxes/mbx_abc123/inbox/messages/eml_123/move \
  -H "Authorization: Bearer $SHIPMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target_role":"archive"}'
```

### Create A Webhook

```bash
curl -X POST https://shipmail.to/api/v1/webhooks \
  -H "Authorization: Bearer $SHIPMAIL_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "url":"https://example.com/api/shipmail",
    "events":["message.received","message.bounced"]
  }'
```

## SDKs

CLI:

```bash
npx -y shipmail-cli --help

export SHIPMAIL_API_KEY="sm_live_..."
shipmail status
shipmail domains create example.com
shipmail mailboxes create --domain-id dom_abc123 --address agent
shipmail messages send --mailbox-id mbx_abc123 --to user@example.com --subject "Hello" --text "Hi there"
shipmail inbox list mbx_abc123 --folder-role inbox --limit 25
```

Use `shipmail api <METHOD> <PATH> --data JSON|@file` for any REST endpoint that does not have a shorthand command.

TypeScript:

```bash
npm install shipmail
```

```ts
import ShipMail from "shipmail";

const client = new ShipMail(process.env.SHIPMAIL_API_KEY!);
const inbox = await client.mailboxes.listInboxMessages("mbx_abc123", {
  folder_role: "inbox",
  limit: 25,
});
```

Python:

```bash
pip install shipmail
```

```py
from shipmail import ShipMail

client = ShipMail("sm_live_...")
inbox = client.mailboxes.list_inbox_messages("mbx_abc123", {
    "folder_role": "inbox",
    "limit": 25,
})
```

## MCP

Install the MCP server in stdio-compatible hosts with:

```bash
npx -y shipmail-mcp
```

Set `SHIPMAIL_API_KEY` in the MCP server environment. The MCP server exposes read/write tools for domains, mailboxes, inbox messages, messages, threads, webhooks, suppressions, and status. It also exposes read-only resources for status, domains, mailboxes, mailbox folders, identities, rules, inbox message lists, inbox threads, messages, and threads. Domain registration is intentionally not exposed as an MCP tool because it charges a saved payment method.
