# Outreach Emails

## Use case

Draft personalized emails, review them, and send from your connected inbox.

## Endpoint

```http
POST https://api-public.clodo.ai/api/public/v1/emails/
```

Send your API key in the `x-api-key` header. See [Authentication](https://docs.clodo.ai/api-reference/authentication).

> This endpoint returns `202 Accepted`. Poll the resource to follow its progress. Outreach does not require a webhook signing secret.

## Pricing

See [Credits & Pricing](https://docs.clodo.ai/guides/credits-and-pricing) for credit costs and charging behavior.

## Errors

For error responses and retry guidance, see [Handling Errors](https://docs.clodo.ai/api-reference/errors).

Create AI-drafted outreach emails, review them, and send them from your own connected inbox — the full draft → review → approve → send loop over the API. **2 credits per drafted email**, charged when the draft succeeds. Reviewing, editing, approving, cancelling, and reading are free.

Emails send from a mailbox you've connected in the Clodo web app (see [Sending Accounts](https://docs.clodo.ai/api-reference/endpoint/sending-accounts)), and every email you create here also appears on your Emails page in the app — same review queue, same thread history, same open and reply tracking.

This is not a raw email-sending API: you supply a contact and instructions, Clodo drafts the copy. Every recipient is saved as a lead in your workspace.

## Lifecycle

```
POST /emails/            -> 202  status: drafting
GET  /emails/{id}/       -> poll until status: pending_review
PATCH /emails/{id}/      -> optional draft edits
POST /emails/{id}/approve/ -> status: queued (then sending -> sent)
```

| Status | Meaning |
|---|---|
| `drafting` | The draft is being written (typically 10–60s). |
| `pending_review` | Draft ready — waiting for your approval. Expires after 7 days (see `review_expires_at`). |
| `queued` | Approved; waiting for its send slot. |
| `sending` / `sent` | In flight / delivered to your provider. |
| `failed` | Drafting or sending failed (see `error`). Failed drafts are not charged. |
| `cancelled` | Cancelled by you, or expired unapproved. |

Pass `"review": "none"` at create to skip the review gate — the draft goes straight to `queued` with an automatically chosen send time. The default (`"required"`) is recommended: nothing sends without an explicit approve.

## Create — `POST /emails/`

| Field | Type | Notes |
|---|---|---|
| `to.email` | string | Required. Recipient address — becomes/updates a lead in your workspace. |
| `to.first_name` | string | Required. |
| `to.last_name` | string | Optional. |
| `to.company_name` | string | Optional but recommended — improves the draft. |
| `to.professional_url` | string | Optional LinkedIn URL. |
| `to.context` | string | Optional free-text grounding, ≤1000 chars (e.g. "raised Series B last month"). |
| `instructions` | string | Required, ≤2000 chars. What the email should say/do. |
| `from_account` | string | Optional `ea_...` id (see [Sending Accounts](https://docs.clodo.ai/api-reference/endpoint/sending-accounts)). Defaults to your least-loaded connected account. |
| `reply_to` | string | Optional Reply-To address. Must be one of **your** connected email accounts; anything else is a `400`. |
| `cc` | string[] | Optional CC recipients, max 3. Visible to everyone on the thread. A reply **from** a CC'd address is not treated as the lead replying. |
| `bcc` | string[] | Optional BCC recipients, max 3 (e.g. a CRM logging address). Never visible to the other recipients. |
| `review` | string | `"required"` (default) or `"none"`. |

```bash
curl -X POST https://api-public.clodo.ai/api/public/v1/emails/ \
  -H "x-api-key: ck_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": {
      "email": "jackie@acme.com",
      "first_name": "Jackie",
      "company_name": "Acme",
      "context": "spoke at SaaStr about PLG onboarding"
    },
    "instructions": "Casual note asking if she is open to hearing about our founding PM role."
  }'
```

Returns `202`:

```json
{ "id": "em_1f0c9a...", "status": "drafting", "created_at": "2026-07-13T00:00:00Z" }
```

`409 conflict` means you have no usable sending account — connect one in the Clodo web app first.

## Read — `GET /emails/{id}/`

Poll this while `drafting`; afterwards it's the live state of the email (opens, replies, schedule).

```json
{
  "id": "em_1f0c9a...",
  "status": "pending_review",
  "to": { "email": "jackie@acme.com", "name": "Jackie" },
  "from_email": "you@yourcompany.com",
  "subject": "Founding PM at Acme?",
  "body_plain": "Hi Jackie, ...",
  "body_html": "<p>Hi Jackie, ...</p>",
  "instructions": "Casual note asking...",
  "created_at": "2026-07-13T00:00:00Z",
  "scheduled_for": null,
  "sent_at": null,
  "opened_at": null,
  "open_count": 0,
  "replied_at": null,
  "review_expires_at": "2026-07-20T00:00:10Z",
  "error": null
}
```

## List — `GET /emails/`

Paginated, newest first. Filters: `?status=<any wire status>`, `?since=<ISO 8601>`, `?page=`, `?page_size=` (default 50, max 200). Returns `{count, page, page_size, total_pages, results}`. Only emails created through the API appear here.

```bash
curl "https://api-public.clodo.ai/api/public/v1/emails/?status=replied&since=2026-07-01T00:00:00Z" \
  -H "x-api-key: ck_live_..."
```

## Edit — `PATCH /emails/{id}/`

Allowed while `pending_review` or `queued` (approved but not yet sent — including scheduled follow-up steps of a running sequence). Send `subject` and/or one of `body_plain` / `body_html` (not both). HTML is sanitized server-side. Editing while `pending_review` extends the 7-day review window. Once a message is `sending` or `sent` the edit returns `409`.

```bash
curl -X PATCH https://api-public.clodo.ai/api/public/v1/emails/em_1f0c9a.../ \
  -H "x-api-key: ck_live_..." \
  -H "Content-Type: application/json" \
  -d '{"subject": "Quick question about Acme"}'
```

## Approve — `POST /emails/{id}/approve/`

Only while `pending_review`. Returns the updated email.

| Body | Behavior |
|---|---|
| `{"schedule": "best_time"}` | Default. Clodo picks the optimal send time for the recipient. |
| `{"schedule": "now"}` | Next available send slot. |
| `{"schedule": "at", "send_at": "2026-07-14T16:00:00Z"}` | Fixed UTC time. |

## Cancel — `POST /emails/{id}/cancel/`

Allowed while `drafting`, `pending_review`, or `queued`. Cancelling mid-draft costs nothing; cancelling an already-drafted email does not refund the 2 credits (the drafting work happened).

## Status mapping

| Outcome | HTTP | Charged |
|---|---|---|
| Draft created | `202` | 2 credits when the draft succeeds |
| Draft failed | — (`status: failed` on poll) | 0 |
| Invalid input | `400 invalid_request` | 0 |
| No usable sending account | `409 conflict` | 0 |
| Edit/approve/cancel in wrong state | `409 conflict` | 0 |
| Unknown `em_` id | `404 not_found` | 0 |

## Notes

- Webhooks are **optional** for these endpoints — polling is first-class. If you never register a webhook secret, everything above still works.
- Daily send limits on your connected accounts always apply; approving more than the day's limit queues the remainder for the following days.
- Sends stop automatically when the recipient replies (visible via `replied_at`).

## See also

- [Sending Accounts](https://docs.clodo.ai/api-reference/endpoint/sending-accounts)
- [Credit Semantics](https://docs.clodo.ai/guides/credits-and-pricing)
- [Async Polling](https://docs.clodo.ai/guides/async-polling)
