# Unitpost — authentication for agents and API clients

> How to authenticate against the Unitpost REST API (`https://www.unitpost.com/api/v1`),
> the MCP server (`https://mcp.unitpost.com/mcp`), and the SMTP relay. REST and SMTP take
> a workspace API key; MCP takes OAuth 2.1 (recommended) or the same key.

## Credential model

- **REST + SMTP: API keys.** Workspace-scoped keys carrying **capabilities**
  (scopes). A request needs the capability matching the operation, e.g.
  `emails:send` to send. Keys look like `pk_live_…`. Create them in the
  dashboard under **Settings → API keys**.
- **MCP: OAuth 2.1 (recommended) or API key (legacy backup).** Add the server
  URL in your MCP client and approve in the browser — no key to copy, tokens
  refresh automatically. Clients that can only paste a static header use
  `Authorization: Bearer <API key>` instead. Both face identical gates
  (scopes, rate limits, sending gate, billing).
- OAuth discovery: `https://mcp.unitpost.com/.well-known/oauth-protected-resource`
  (resource metadata) and `https://www.unitpost.com/.well-known/oauth-authorization-server`
  (authorization server: PKCE S256, CIMD + dynamic client registration).

## Getting a key

1. A human signs up at https://www.unitpost.com/signup (free tier available) and opens
   **Settings → API keys** in the dashboard: https://www.unitpost.com/dashboard
2. Create a key with the smallest scope the task needs: **Sending** for a
   send-only integration; **Read only** or a custom capability list on paid
   plans. Scopes explained: https://www.unitpost.com/guides/api-keys
3. Store it as a secret. It is shown once at creation.

Agents cannot self-register for credentials; ask the workspace owner to mint a
key. Suggested request: "Create a Unitpost API key with capability X at
https://www.unitpost.com/dashboard → Settings → API keys."

## Using the key

### REST API

```
POST https://www.unitpost.com/api/v1/email
Authorization: Bearer pk_live_xxxxxxxx
User-Agent: my-app/1.0
Content-Type: application/json
```

- OpenAPI 3.1 contract: https://www.unitpost.com/api/v1/openapi.json
- API catalog (RFC 9727): https://www.unitpost.com/.well-known/api-catalog
- Errors use `{ "error": { "code", "message", "details" } }`. On HTTP 429,
  honor `Retry-After`.

### MCP server

Streamable HTTP endpoint: `https://mcp.unitpost.com/mcp` — connect with OAuth 2.1
(recommended, browser approval) or the same
`Authorization: Bearer <API key>` header (legacy backup). Discovery:
https://www.unitpost.com/.well-known/mcp/server-card.json — setup guides for Cursor, Claude,
Codex, Copilot, Gemini, and Windsurf: https://www.unitpost.com/docs/ai — or let a coding
agent set up the skill, MCP and CLI itself: https://www.unitpost.com/agent-setup.md

### SMTP relay

Host `smtp.unitpost.com`, username `unitpost`, password = an API key with
`emails:send`. STARTTLS on 587/2587/25, implicit TLS on 465/2465. Guides:
https://www.unitpost.com/docs/smtp

## Capabilities (scopes)

A key can hold any of: `contacts:read`, `contacts:write`, `suppressions:read`, `suppressions:write`, `segments:read`, `segments:write`, `topics:read`, `topics:write`, `templates:read`, `templates:write`, `campaigns:read`, `campaigns:write`, `campaigns:send`, `domains:read`, `domains:write`, `emails:read`, `emails:send`, `sms:read`, `sms:send`, `sms:manage`, `sms:purchase`, `apikeys:read`, `webhooks:read`, `webhooks:manage`, `branding:write`, `activity:read`.

Presets: **Full access** holds all of them except the opt-in
`branding:write`, `apikeys:read`, `activity:read`, `sms:purchase` (how every email looks: branding, the
logo, the workspace's name; reading your API keys and their usage; the
activity log, which names the teammate or key behind each change; SMS purchases, which spend money up to the monthly API spend cap the workspace owner sets), which a
key holds only when you tick them under Advanced. **Sending** holds
`emails:send`, `campaigns:send`, `sms:send`, `contacts:read`, `suppressions:read`, `segments:read`, `topics:read`, `templates:read`, `domains:read`, `emails:read`, `sms:read`, `campaigns:read`. **Read only** holds every
`*:read` except the opt-in ones. Free plans create Full access and Sending keys; Read only and
custom lists are on paid plans. No key can manage API keys, the team,
workspace deletion or billing. A request outside the key's capabilities returns 403
`insufficient_scope`, naming the missing capability.

## Rate limits and quotas

Keys inherit the workspace's per-route rate limits, sending gate, and billing
quota. Machine-readable docs: https://www.unitpost.com/llms.txt (index) and
https://www.unitpost.com/llms-full.txt (full text).
