Start free

API reference

Email

Send email with a required Idempotency-Key, list the sends in your key's environment and follow each one's status: delivered, bounced or complained.

  • 3 operations
  • Base URLhttps://api.messages.ccxcompany.co
  • AuthenticationBearer with your API key

The technical text below comes from the public contract, openapi.json, in the language the contract was written in.

Lista os emails enviados

GET/v2/email/messages

Devolve os emails do AMBIENTE da credencial: uma chave ccx_test_* nunca vê envio de produção, e vice-versa.

O corpo do email não está aqui e não estará: guardamos bodyBytes, não o conteúdo.

Parameters

FieldInTypeDescription
statusoptionalquerystringValues:queuedsentdeliveredbouncedcomplainedfailed
tooptionalquerystring
campaignIdoptionalquerystring
limitoptionalqueryinteger
skipoptionalqueryinteger

Responses

  • 200Default Response

    Response fields and example
    FieldTypeDescription
    itemsrequiredobject[]
    items[].idrequiredstring
    items[].organizationIdrequiredstring
    items[].envoptionalstringValues:livetestDefault:live
    items[].torequiredstring · email
    items[].fromrequiredstring
    items[].subjectrequiredstring
    items[].bodyBytesrequiredinteger
    items[].statusrequiredstringValues:queuedsentdeliveredbouncedcomplainedfailed
    items[].reasonoptionalstringValues:invalid_addressmailbox_fullsuppressedcontent_rejectedcomplaintprovider_errorno_verified_sender
    items[].contactIdoptionalstring
    items[].campaignIdoptionalstring
    items[].metadataoptionalobjectMetadados de correlação do seu sistema (ex.: customerId, journeyId), devolvidos intactos em todo webhook desta mensagem. Até 20 chaves; chave começa por letra e usa [A-Za-z0-9_.-] (até 64); valor é texto (até 256), número ou booleano. Não envie dado pessoal aqui.
    items[].sentAtoptionalstring · date-time
    items[].deliveredAtoptionalstring · date-time
    items[].failedAtoptionalstring · date-time
    items[].createdAtrequiredstring · date-time
    items[].updatedAtrequiredstring · date-time
    totalrequiredinteger
    JSON
    {  "items": [    {      "id": "string",      "organizationId": "string",      "env": "live",      "to": "user@example.com",      "from": "string",      "subject": "string",      "bodyBytes": 0,      "status": "queued",      "reason": "invalid_address",      "contactId": "string",      "campaignId": "string",      "metadata": {},      "sentAt": "2026-10-16T12:00:00.000Z",      "deliveredAt": "2026-10-16T12:00:00.000Z",      "failedAt": "2026-10-16T12:00:00.000Z",      "createdAt": "2026-10-16T12:00:00.000Z",      "updatedAt": "2026-10-16T12:00:00.000Z"    }  ],  "total": 0}
  • 400RFC 7807 problem details for BAD_REQUEST (400).

  • 401RFC 7807 problem details for UNAUTHORIZED (401).

  • 403RFC 7807 problem details for FORBIDDEN (403).

Error responses follow RFC 7807 (application/problem+json), with a stable code in the code field. See the error codes

curl example

cURL
curl 'https://api.messages.ccxcompany.co/v2/email/messages' \  -H "Authorization: Bearer $CCX_API_KEY"
Required fields only. Swap the sample values for your own.

Envia um email

POST/v2/email/messages

Envio síncrono: a resposta chega depois de o provedor aceitar (ou recusar) a mensagem. Aceite não é entrega — entrega, bounce e reclamação são assíncronos e chegam no seu webhook.

`Idempotency-Key` é obrigatória. Sem ela o envio para com 400. Não derivamos uma do corpo: dois emails idênticos de propósito não podem virar um.

Ambiente: vem da credencial. Uma chave ccx_test_* cai no sandbox, e env: "test" sai carimbado na resposta. Não há como pedir um ambiente pelo corpo do request.

O sandbox mente em exatamente duas coisas, e a lista é fechada:

  1. Nada chega em caixa de entrada nenhuma.
  2. O envio de sandbox não conta no seu volume mensal. O preço em billing.coins é o real — mas um envio de teste nunca desloca o seu TIER.

Fora dessas duas, o sandbox é o produto: cobra de verdade (na carteira de sandbox), mesmo status, mesma latência.

Destinatários mágicos (sandbox): são os endereços do mailbox simulator que a própria SES opera — não uma tabela nossa. Em produção eles produzem exatamente os mesmos desfechos.

todesfecho
success@simulator.amazonses.comaceito; entrega
bounce@simulator.amazonses.comaceito; bounce assíncrono
complaint@simulator.amazonses.comaceito; reclamação assíncrona
ooto@simulator.amazonses.comaceito; resposta automática de ausência
suppressionlist@simulator.amazonses.comrecusa síncrona — endereço na lista de supressão da conta
qualquer outroaceito; entrega

Repare que só suppressionlist falha no POST. Bounce e reclamação são decisão do provedor e chegam DEPOIS — tratá-los no catch é o erro nº1 de quem integra com email.

Preço: billing.coins é o custo do envio, em coins (1 coin = R$ 0,0001). O email não tem faixa de volume (Cl. 8.8): é preço fixo por destinatário. Saldo insuficiente é 402.

Corpo: informe html, text, ou os dois. O corpo não é armazenado — guardamos bodyBytes, e não o conteúdo.

Ou envie por template. Com templateId, o assunto e o corpo vêm do template salvo — inclusive os escritos em MJML, que já ficam compilados. Preencha as {{variáveis}} com variables:

{ "to": "cliente@exemplo.com", "templateId": "etpl_…", "variables": { "nome": "Marina", "empresa": "Padaria Silva" } }

Com templateId, subject é opcional — informá-lo sobrescreve o do template (útil para A/B). Variável declarada no template e não informada aqui cai no example dele; sem exemplo, o placeholder sai vazio (nunca chega {{nome}} cru na caixa de entrada).

Opt-out: destinatário cujo contato pediu para não receber comunicação é recusado com 422 e meta.motivo: "opt_out". Para e-mail transacional (senha, pedido), envie transactional: true.

Permissão: email:send.

Request bodyapplication/json

FieldTypeDescription
torequiredstring · email
subjectoptionalstring
templateIdoptionalstring
variablesoptionalobject
htmloptionalstringCorpo HTML. Obrigatório informar html OU text (pelo menos um).
textoptionalstringCorpo texto puro. Obrigatório informar html OU text (pelo menos um).
fromoptionalstring
contactIdoptionalstring
campaignIdoptionalstring
metadataoptionalobjectMetadados de correlação do seu sistema (ex.: customerId, journeyId), devolvidos intactos em todo webhook desta mensagem. Até 20 chaves; chave começa por letra e usa [A-Za-z0-9_.-] (até 64); valor é texto (até 256), número ou booleano. Não envie dado pessoal aqui.
transactionaloptionalbooleantrue para e-mail transacional (senha, pedido): sai mesmo para quem fez opt-out. Ausente ⇒ comunicação, bloqueada para quem saiu.
Full body example
JSON
{  "to": "user@example.com",  "subject": "string",  "templateId": "string",  "variables": {},  "html": "string",  "text": "string",  "from": "string",  "contactId": "string",  "campaignId": "string",  "metadata": {},  "transactional": true}

Responses

  • 201Default Response

    Response fields and example
    FieldTypeDescription
    idrequiredstring
    statusrequiredstringValues:queuedsentdeliveredbouncedcomplainedfailed
    envrequiredstringValues:livetest
    torequiredstring
    fromrequiredstring
    subjectrequiredstring
    bodyBytesrequiredinteger
    replayedrequiredboolean
    billingoptionalobject
    billing.coinsrequiredinteger
    contactIdoptionalstring
    campaignIdoptionalstring
    metadataoptionalobjectMetadados de correlação do seu sistema (ex.: customerId, journeyId), devolvidos intactos em todo webhook desta mensagem. Até 20 chaves; chave começa por letra e usa [A-Za-z0-9_.-] (até 64); valor é texto (até 256), número ou booleano. Não envie dado pessoal aqui.
    createdAtrequiredstring · date-time
    sentAtoptionalstring · date-time
    JSON
    {  "id": "string",  "status": "queued",  "env": "live",  "to": "string",  "from": "string",  "subject": "string",  "bodyBytes": 0,  "replayed": true,  "billing": {    "coins": 0  },  "contactId": "string",  "campaignId": "string",  "metadata": {},  "createdAt": "2026-10-16T12:00:00.000Z",  "sentAt": "2026-10-16T12:00:00.000Z"}
  • 400RFC 7807 problem details for BAD_REQUEST (400).

  • 401RFC 7807 problem details for UNAUTHORIZED (401).

  • 402RFC 7807 problem details for PAYMENT_REQUIRED (402).

  • 403RFC 7807 problem details for FORBIDDEN (403).

  • 412RFC 7807 problem details for PRECONDITION_FAILED (412).

  • 422RFC 7807 problem details for VALIDATION_ERROR (422).

  • 502RFC 7807 problem details for DEPENDENCY_FAILED (502).

Error responses follow RFC 7807 (application/problem+json), with a stable code in the code field. See the error codes

curl example

cURL
curl -X POST 'https://api.messages.ccxcompany.co/v2/email/messages' \  -H "Authorization: Bearer $CCX_API_KEY" \  -H "Idempotency-Key: order-4821" \  -H "Content-Type: application/json" \  -d '{    "to": "user@example.com"  }'
Required fields only. Swap the sample values for your own.

Lê um email pelo id

GET/v2/email/messages/{id}

O status conta a história do envio: queued → sent (o provedor aceitou) → delivered | bounced | complained. failed é recusa antes de sair.

404 também é a resposta para um email de outro ambiente ou de outra organização — distinguir “não existe” de “não é seu” contaria a existência de dado alheio.

Parameters

FieldInTypeDescription
idrequiredpathstring

Responses

  • 200Default Response

    Response fields and example
    FieldTypeDescription
    idrequiredstring
    organizationIdrequiredstring
    envoptionalstringValues:livetestDefault:live
    torequiredstring · email
    fromrequiredstring
    subjectrequiredstring
    bodyBytesrequiredinteger
    statusrequiredstringValues:queuedsentdeliveredbouncedcomplainedfailed
    reasonoptionalstringValues:invalid_addressmailbox_fullsuppressedcontent_rejectedcomplaintprovider_errorno_verified_sender
    contactIdoptionalstring
    campaignIdoptionalstring
    metadataoptionalobjectMetadados de correlação do seu sistema (ex.: customerId, journeyId), devolvidos intactos em todo webhook desta mensagem. Até 20 chaves; chave começa por letra e usa [A-Za-z0-9_.-] (até 64); valor é texto (até 256), número ou booleano. Não envie dado pessoal aqui.
    sentAtoptionalstring · date-time
    deliveredAtoptionalstring · date-time
    failedAtoptionalstring · date-time
    createdAtrequiredstring · date-time
    updatedAtrequiredstring · date-time
    JSON
    {  "id": "string",  "organizationId": "string",  "env": "live",  "to": "user@example.com",  "from": "string",  "subject": "string",  "bodyBytes": 0,  "status": "queued",  "reason": "invalid_address",  "contactId": "string",  "campaignId": "string",  "metadata": {},  "sentAt": "2026-10-16T12:00:00.000Z",  "deliveredAt": "2026-10-16T12:00:00.000Z",  "failedAt": "2026-10-16T12:00:00.000Z",  "createdAt": "2026-10-16T12:00:00.000Z",  "updatedAt": "2026-10-16T12:00:00.000Z"}
  • 400RFC 7807 problem details for BAD_REQUEST (400).

  • 401RFC 7807 problem details for UNAUTHORIZED (401).

  • 403RFC 7807 problem details for FORBIDDEN (403).

  • 404RFC 7807 problem details for NOT_FOUND (404).

Error responses follow RFC 7807 (application/problem+json), with a stable code in the code field. See the error codes

curl example

cURL
curl 'https://api.messages.ccxcompany.co/v2/email/messages/<id>' \  -H "Authorization: Bearer $CCX_API_KEY"
Required fields only. Swap the sample values for your own.

Stuck on a route? Talk to the people who run the API.

Sign up through the site and get a US$5 test credit.