Outreach Emails
Draft personalized emails, review them, and send from your connected inbox.
#Use case
Draft personalized emails, review them, and send from your connected inbox.
#Endpoint
POST https://api-public.clodo.ai/api/public/v1/emails/Send your API key in the x-api-key header. See 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 for credit costs and charging behavior.
#Errors
For error responses and retry guidance, see Handling 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), 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). 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". |
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:
{ "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).
{
"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.
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.
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).