CarlyEmail docs
curl -X POST "https://api.carlyemail.com/v0/inboxes/$INBOX_ID/messages/send" \
  -H "Authorization: Bearer $CARLYEMAIL_API_KEY" \
  -H 'content-type: application/json' \
  -d '{
    "to": ["someone@example.org"],
    "cc": [],
    "subject": "Hello",
    "text": "Plain body",
    "html": "<p>HTML body</p>"
  }'

Supply text, html, or both. Both is best — some clients will only render one.

The response carries message_id and thread_id. The message also lands in the inbox labelled sent, so a thread reads as a conversation rather than only the half that came back.

Four things refuse a send

In the order you will meet them:

  1. The organization is unverified403 organization_unverified. Confirm the owner email. See limits.
  2. Quota exceeded429 with an exact Retry-After.
  3. The recipient is suppressed — they hard-bounced or complained. See suppression.
  4. The key lacks message_send403 insufficient_permissions.

Replying

Reply rather than send, so the conversation threads in the recipient's client too:

curl -X POST "https://api.carlyemail.com/v0/messages/$MESSAGE_ID/reply" \
  -H "Authorization: Bearer $CARLYEMAIL_API_KEY" \
  -H 'content-type: application/json' \
  -d '{"text": "Thanks — looking into it now.", "reply_all": false}'

Scheduling

send_at accepts an ISO-8601 timestamp to send later.