Email messages
Write first by email
Sends the email and opens a case (or reuses the open email case of the contact), so the answer comes back into that case and the agent continues. No 24 hour window. It sends an email to a real person and cannot be undone: use dryRun=true first, which runs the same checks (recipient, opt-out, allowlist, verified sender domain, open case and its destination) and answers 200 with the message as it would be created, sending and saving nothing; its id is not saved. A contact that opted out answers 202 with status skipped and skipReason opted_out. 422 sender_domain_not_verified without a verified domain. onReply.instructions is the context the agent gets if the contact answers. To send files, open the case with POST /v2/cases (channel email) and use POST /v2/cases/{id}/messages.
Required scope: email:write.
query Parameters
dryRunWhen true, the request goes through the same validation as the real one and is answered with what would happen (always 200), and nothing is saved, sent or charged. The answer has the same shape as the real one plus dryRun: true; an id in it is not saved. It does not use the Idempotency-Key.
Headers
Lelemon-Subaccount^sub_[0-9A-Za-z]{22}…The subaccount (sub_…) this request acts on. Only for the keys of a platform account; without it the request acts on the account itself.
Idempotency-KeyMakes the request safe to retry. Once it starts running, its final response (2xx, 4xx or 5xx) is kept for 24 hours and the same key gets it back, without repeating the effect. A request rejected before it runs leaves the key free. A replayed create omits the secret. The same key with a different request is rejected with 409 idempotency_key_reused.
Write first by email › Request Body
Exactly one of contactId, externalRef or email.
subject^[^\r\n]*$ · requiredtextfromThe sender. It must belong to a verified domain. Defaults to the first verified domain.
Who continues if they answer. The agent needs the email channel. Without agentId or stageId the case reuses the open email case of the contact.
Write first by email › Responses
dryRun=true: the message as it would be created; nothing is sent.
objectiddirectionstatuscaseIdcontactIdsubjectfromtoskipReasonWhy it was skipped: opted_out, recipient_not_allowed, no_email, human_in_control, cooldown, no_verified_domain or open_case_elsewhere.
createdAtdryRunPresent and true when the request had dryRun=true.
Retrieve an email message
status: queued, sent, delivered, bounced, failed (with failure.code), skipped (with skipReason), received or rejected.
Required scope: email:read.
path Parameters
id^eml_[0-9A-Za-z]{22}… · requiredThe id of the email message (eml_…).
Headers
Lelemon-Subaccount^sub_[0-9A-Za-z]{22}…The subaccount (sub_…) this request acts on. Only for the keys of a platform account; without it the request acts on the account itself.
Retrieve an email message › Responses
objectiddirectionstatuscaseIdcontactIdsubjectfromtoskipReasonWhy it was skipped: opted_out, recipient_not_allowed, no_email, human_in_control, cooldown, no_verified_domain or open_case_elsewhere.
createdAt