Guia do desenvolvedorMigração
Migrar do Resend
Guia para sair do Resend e ir para o Couryo. A chamada de envio é quase igual (from, to, subject, html, text, tags, scheduled_at, Idempotency-Key, lote de 100), com o mapeamento de eventos, webhooks, audiences, React Email e a troca de DNS.
Quem vem do Resend reconhece quase tudo: o corpo do envio, o lote de 100, a Idempotency-Key, o agendamento com cancelamento e os webhooks assinados. As diferenças estão nos detalhes abaixo. Siga a ordem segura da migração e use este guia para traduzir cada parte.
A chamada de envio#
curl https://api.resend.com/emails \
-H "Authorization: Bearer $RESEND_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"from": "Loja <pedidos@exemplo.com.br>",
"to": ["ana@exemplo.com.br"],
"subject": "Pedido 1042 confirmado",
"html": "<p>Obrigado, Ana!</p>",
"tags": [{ "name": "categoria", "value": "pedido" }]
}'curl https://api.couryo.com/v1/emails \
-H "Authorization: Bearer $COURYO_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: pedido-1042-confirmacao" \
-d '{
"from": "Loja <pedidos@exemplo.com.br>",
"to": ["ana@exemplo.com.br"],
"subject": "Pedido 1042 confirmado",
"html": "<p>Obrigado, Ana!</p>",
"text": "Obrigado, Ana!",
"tags": { "categoria": "pedido" }
}'O Resend responde { "id": "..." }; o Couryo responde 202 { "id": "msg_...", "status": "queued" }, só depois de o e-mail entrar na fila.
Campos#
| Resend | Couryo | Observação |
|---|---|---|
from, to, cc, bcc, reply_to, subject, html, text |
os mesmos nomes | até 50 destinatários somando to, cc e bcc |
react (SDK) |
html e text |
renderize com o render do React Email antes de enviar (veja abaixo) |
tags: [{ name, value }] |
tags: { name: value } |
objeto, não lista |
headers |
headers |
cabeçalhos da plataforma são ignorados |
attachments[] (filename, content, path, content_type) |
attachments[] (filename, content em Base64, content_type, content_id) |
sem path: baixe o arquivo e mande o conteúdo |
scheduled_at (ISO ou texto como "in 1 hour") |
scheduled_at (ISO 8601 com fuso, até 30 dias) |
só a data em ISO |
PATCH /emails/{id} e POST /emails/{id}/cancel |
PATCH /v1/emails/{id} e POST /v1/emails/{id}/cancel |
o mesmo desenho |
POST /emails/batch (até 100) |
POST /v1/emails/batch (até 100) |
o Couryo valida cada item sozinho e devolve um resultado por item |
Idempotency-Key |
Idempotency-Key |
24 horas; mesmo corpo devolve a mesma resposta, corpo diferente 409 |
| (sem equivalente) | metadata |
dados seus que voltam em todo webhook, como { "pedido_id": "1042" } |
| (sem equivalente) | stream: "marketing" |
descadastro em um clique incluído e supressão separada do transacional |
React Email#
O Couryo recebe HTML pronto. Com React Email, renderize antes:
import { render } from "@react-email/render";
import { PedidoConfirmado } from "./emails/pedido-confirmado";
const html = await render(<PedidoConfirmado nome="Ana" />);
const text = await render(<PedidoConfirmado nome="Ana" />, { plainText: true });
await fetch("https://api.couryo.com/v1/emails", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.COURYO_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": "pedido-1042" },
body: JSON.stringify({ from: "Loja <pedidos@exemplo.com.br>", to: "ana@exemplo.com.br", subject: "Pedido 1042 confirmado", html, text }),
});Para e-mails que o time edita sem deploy, crie templates salvos ou use o editor visual e mande template com variables.
Eventos e webhooks#
| Resend | Couryo |
|---|---|
email.sent |
sent |
email.delivered |
delivered |
email.delivery_delayed |
deferred |
email.bounced |
bounced |
email.complained |
complained |
email.opened |
opened |
email.clicked |
clicked |
email.failed |
failed |
Os dois assinam no padrão Standard Webhooks: o Couryo usa os cabeçalhos webhook-id, webhook-timestamp e webhook-signature (HMAC-SHA256 com o segredo whsec_...). Se o seu receptor confere a assinatura com uma biblioteca do padrão, troque o segredo e o prefixo dos cabeçalhos. O type do corpo vem sem o prefixo email. (por exemplo, "type": "bounced") e o data traz email_id, recipient, o código SMTP, a resposta crua do destino e a explicação em linguagem simples, no idioma da conta (webhooks).
Audiences, contatos e tópicos#
- Exporte cada audience em CSV e importe no Couryo, com a confirmação de consentimento. Quem já tinha se descadastrado: cadastre como supressão de marketing antes (copiar as supressões).
- Os tópicos do Resend existem no Couryo com o mesmo nome: crie em Contatos > Tópicos ou em
POST /v1/topics. O rodapé de marketing leva à página de preferências. - Broadcasts viram campanhas, com público por tag, atributo ou tópico.
DNS#
O Resend publica a chave DKIM num registro próprio (resend._domainkey) e o return path no subdomínio send. Nenhum deles conflita com os do Couryo (couryo1._domainkey, couryo2._domainkey e bounces), então os dois ficam publicados juntos durante a migração.
- Publique os registros do Couryo e espere o domínio ficar verificado.
- Mantenha o DMARC que você já tem; para receber os relatórios no agente de entregabilidade, acrescente
mailto:reports@dmarc.couryo.comaorua. - Depois que todo o tráfego estiver no Couryo e se passarem 7 dias, apague o
resend._domainkeye os registros do subdomíniosend. Não mexa no MX nem no SPF das suas caixas de e-mail.