Test Emails
Send repeat previews to the fixed shared test inbox, including your saved signature and optional attachments. Restricted to three pilot accounts.
#Use case
Check your email copy, saved signature or banner, and attachments by sending repeated previews to hello@clodo.ai. This restricted endpoint is available only to the three verified clodo accounts belonging to Sid, Rithvik, and Natalie. Teammates, sender aliases, and other accounts with matching email domains do not gain access.
These are real emails to the shared inbox. Supply finished copy; clodo does not generate a draft or wait for approval. The POST queues the send immediately. Test records are separate from prospect outreach: they neither create prospect correspondence or reservations nor clear existing outreach history. Real-prospect duplicate protections are unchanged.
#Endpoint
POST https://api-public.clodo.ai/api/public/v1/test-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 — POST /test-emails/
Use the base URL https://api-public.clodo.ai/api/public/v1/ and authenticate with your x-api-key. Select one of your own connected Sending Accounts.
| Field | Type | Notes |
|---|---|---|
from_account |
string | Required ea_... account ID owned by the authenticated user. Its selected sending address or alias is used. |
subject |
string | Required, nonempty, at most 300 characters. Control characters are rejected. |
body_plain |
string | Nonempty finished text, at most 50,000 characters. Supply exactly one body format. |
body_html |
string | Nonempty finished HTML, at most 50,000 characters. Sanitized before sending; supply instead of body_plain. |
attachments |
array | Optional, default []. At most 5 files and 1 MiB decoded bytes combined. See Attachments below. |
All other fields are rejected, including to, cc, bcc, reply_to, review, and scheduling fields. The recipient cannot be changed, even to another personal test address.
The selected account must be connected and usable. clodo snapshots its sending address and resolved saved signature when creating the record; the signature, including any saved banner, is appended during sending. Supply only your message body to avoid duplicating the signature. An unavailable or changed sending account blocks submission rather than silently choosing another sender.
#Required idempotency header
Every POST requires Idempotency-Key: 1–128 ASCII letters, digits, periods, underscores, colons, or hyphens. Keys belong to the authenticated user, across that user's API keys.
- Reuse the same key and request content after a timeout or lost response. clodo returns the original record; it does not start another send once the worker has claimed it.
- Reusing the same key with different validated content returns
409 conflict. - Use a new key only for a deliberately new preview. A new key can send another real email, even when the content matches a previous preview.
- If the result is
unknown, do not retry with a new key. The email may already have been sent. Inspect the shared inbox and contact support to reconcile the original record.
Requests are compared after input validation and normalization. Preserve your original payload when retrying. This endpoint's durable per-user retry behavior is specific to test emails.
The following examples are equivalent. Replace the sample account ID with one returned for your own account. Keep the key unchanged when retrying this preview; running these examples with a different key requests another send.
curl -X POST https://api-public.clodo.ai/api/public/v1/test-emails/ \
-H "x-api-key: ck_live_..." \
-H "Idempotency-Key: signature-preview-001" \
-H "Content-Type: application/json" \
-d '{
"from_account": "ea_0123456789abcdef",
"subject": "Signature and attachment preview",
"body_plain": "This is a preview for the shared test inbox.",
"attachments": [{
"filename": "notes.txt",
"content_type": "text/plain",
"content_base64": "SGVsbG8="
}]
}'New records return 202 Accepted. Same-key requests return 202 while queued or sending, otherwise 200, with the existing record. A successful POST acknowledges the record; poll its status to check submission.
#Read — GET /test-emails/{id}/
The ID is a UUID. Only the user who created the test can read it; sharing the recipient inbox does not grant access to another user's API records.
curl https://api-public.clodo.ai/api/public/v1/test-emails/3c20cc6e-1a2f-4f88-86bf-9030e192309d/ \
-H "x-api-key: ck_live_..."POST and GET return the same fields. Example queued response:
{
"id": "3c20cc6e-1a2f-4f88-86bf-9030e192309d",
"status": "queued",
"to": "hello@clodo.ai",
"from_account": "ea_0123456789abcdef",
"from_email": "you@yourcompany.com",
"subject": "Signature and attachment preview",
"body_html": "<p>This is a preview for the shared test inbox.</p>",
"signature_html": "<p>Your saved signature</p>",
"attachments": [{"filename": "notes.txt", "content_type": "text/plain", "size_bytes": 5}],
"created_at": "2026-10-15T12:00:00Z",
"sent_at": null,
"message_id": null,
"internet_message_id": null,
"error": null
}| Status | Meaning and next step |
|---|---|
queued |
Waiting for the sending worker. Poll; a same-key POST can safely re-enqueue an unclaimed record after a queue interruption. |
sending |
The worker has claimed the one submission attempt. Poll without creating another request. |
sent |
The sending service accepted the email and returned a message identifier. sent_at and at least one of message_id or internet_message_id are populated. This is not proof of inbox delivery; check hello@clodo.ai to verify rendering and files. |
failed |
Blocked before submission, for example by an unavailable sending account. error describes this state. The original request is not automatically retried. |
unknown |
Submission outcome is uncertain, including an interrupted or timed-out send. No automatic resend. Check the shared inbox and reconcile this record before requesting another preview. |
If a record remains queued after a queue or publish outage, repeat the original POST with the same key and content to safely republish it. Automatic recovery from a queue outage is not guaranteed. This recovery applies only before the worker claims the attempt; never use a new key to retry an unknown outcome.
A send still in progress after ten minutes is reported as unknown; it may subsequently become sent if its original attempt completes and is recorded. There is no edit, approve, cancel, or reply operation on test records.
#Attachments
Files use the existing private attachment pilot: attachment access must also be enabled for the authenticated account. Each file requires exactly filename, content_type, and content_base64.
- Maximum 5 nonempty files; each file and all decoded contents combined must fit within 1 MiB (1,048,576 bytes).
- Supported types:
application/pdf(.pdf),image/png(.png),image/jpeg(.jpgor.jpeg),text/plain(.txt), andtext/csv(.csv). Text must be UTF-8. File bytes must match the declared type. - Use standard base64 without whitespace or a data-URL prefix. Filenames must be at most 180 characters, with no paths, control characters, or leading/trailing whitespace.
- These checks validate format, not malware safety. URLs, executable files, and inline attachment images are unsupported.
Contents remain on the private test record. Responses expose only filename, content type, and decoded size; there is no file-content or download endpoint. The saved signature's banner is separate from these file attachments.
#Limits and charging
Each allowed user may create at most 10 new tests per rolling hour and 50 per rolling day, across all their API keys and sending accounts. Replaying an existing key does not consume another test allowance. This test allowance is separate from prospect-outreach daily counters and history; previews do not consume or reset those counters. Normal API gateway request limits still apply to POSTs and reads. Until these routes are explicitly registered in the gateway, they share its catch-all limit of 1 request per minute, burst 2. Poll no more than once per minute and use jittered backoff on 429; see Rate Limits.
No AI drafting runs and no drafting credits are charged for test emails, including failed requests. The endpoint sends the supplied copy through the existing email delivery service.
#Error responses
| HTTP | Meaning |
|---|---|
400 |
Invalid or missing fields/header, unsupported destination fields, invalid attachment, or from_account not owned by the caller. |
401 |
Missing, invalid, or revoked API authentication. |
403 |
The authenticated account is outside the three-account pilot or lacks required API access. |
404 |
Test record missing or owned by another user. |
409 |
Idempotency key reused with different content, selected sender unusable, or incompatible development recipient redirection. |
429 |
Per-user test allowance or API gateway request limit reached. |
5xx |
Request could not complete reliably. Recover using the same key and content; never assume this means no email was sent. |
Application errors use the shared error envelope; gateway throttling can instead return {"message":"Too Many Requests"}. A send failure after the POST is represented by the record's status and error, not a later HTTP error on GET. Do not treat a generic retry suggestion as permission to submit a new key for an uncertain send.