Ritto Mail Docs
Referência da API

Referência da API

A API HTTP do Ritto Mail — compatível com Resend, gerada a partir do código do servidor.

As páginas de endpoint desta seção são geradas a partir das próprias definições de rota da API no momento do build, então sempre refletem o código. A especificação bruta está em /openapi.json (OpenAPI 3.1). As páginas de endpoint estão disponíveis apenas em inglês.

URL base

https://api.ritto.email

Autenticação

Todo endpoint exige uma chave de API criada no painel em app.ritto.email:

Authorization: Bearer rm_...

Chaves têm um nível de permissão: chaves de acesso total podem usar todos os endpoints, chaves de somente envio ficam confinadas a /emails* (qualquer outra coisa retorna 403 restricted_api_key) — e mesmo ali, GET /emails, GET /emails/{id}, GET /emails/{id}/attachments* e DELETE /emails/{id} exigem acesso total, já que as leituras devolvem os corpos e anexos armazenados e todo o arquivo do time. Uma chave também pode ficar restrita a um único domínio, limitando de quais endereços from ela pode enviar.

Compatibilidade com Resend

Os formatos de requisição e resposta correspondem aos da API do Resend, então os SDKs oficiais do Resend funcionam contra o Ritto Mail apontando a URL base para ele. O CI executa o pacote oficial resend do npm contra todos os endpoints como um teste de conformidade. As poucas diferenças restantes são deliberadas e explícitas:

  • Anexos aceitam apenas content em base64 inline — uma URL em path é rejeitada com 422 (nunca é buscada), assim como content_id (imagens inline).
  • Contatos são globais ao time — os endpoints de audience são servidos como aliases de segments, e os endpoints de contato funcionam com ou sem id de audience (veja Contatos).
  • POST /domains aceita um region opcional, que precisa ser uma das regiões de envio que o Ritto Mail oferece — os valores que o schema da requisição lista, a primeira sendo a padrão — e é recusado com 422 caso contrário. Um domínio tem uma região: para mudá-la, exclua o domínio e adicione de novo.
  • Broadcasts suportam canceled, um status fora da união do Resend, e o envio de broadcast, POST /emails e POST /emails/batch podem retornar 403 sending_paused quando sua taxa de bounce ou reclamação cruza os limites de enforcement. Só o envio de broadcast também pode retornar 403 broadcasts_paused enquanto a taxa agregada da plataforma na região de envio do remetente se recupera; é por região, não afeta e-mail transacional e libera sozinho.
  • O envio de um broadcast responde com finishes_at (o instante estimado em que o último e-mail sai, ou null), estimated: true e, quando a audiência passa da capacidade disponível agora, um warning (paced ou queued_behind, com days e uma mensagem). As leituras de broadcast trazem sent_count e um finishes_at ao vivo; um cancelamento responde com canceled_remaining. Uma audiência que precisa de mais de 24 dias de capacidade é recusada com 422 broadcast_too_large. Veja Broadcasts.
  • POST /emails e POST /emails/batch retornam 429 monthly_quota_exceeded no volume incluído do plano quando os envios não podem seguir (sem excedente no Hobby e no Starter, excedente desligado no Pro e no Enterprise); ative o excedente em Cobrança, suba de plano ou espere o período renovar (a mensagem informa a data). Sem assinatura ativa eles retornam 403 plan_required. Um lote é aceito ou recusado por inteiro.
  • POST /contacts, POST /contacts/batch e o alias de audience retornam 403 plan_limit_reached quando um contato novo levaria o time além do limite de contatos do plano (de 1.000 no Hobby a 25.000 no Pro; veja Cobrança). Contatos existentes continuam sendo atualizados; em um lote só os novos falham.
  • GET /usage existe (o Resend não tem endpoint de uso): o plano efetivo, seus limites (emails_per_month, domains, contacts; nenhum plano tem limite diário, então emails_per_day_cap vem null), o total aceito hoje e um objeto period — emails_sent, included, overage_enabled, overage_usd_per_1k, starts_at, ends_at.
  • DELETE /emails/{id} existe (o Resend não tem exclusão de emails).
  • GET /emails/{id} inclui attachments (id, filename, size, content_type; só metadados). GET /emails/{id}/attachments lista os anexos no formato do Resend, e GET /emails/{id}/attachments/{attachment_id} devolve um deles com o arquivo em base64 no campo content (download_url e expires_at são sempre null: não há link assinado de CDN). Ambos respondem 410 attachments_purged depois que a política de retenção removeu o conteúdo do email.
  • Rotas inexistentes respondem 404 not_found no mesmo formato JSON de erro das demais.
  • headers personalizados seguem uma lista de permitidos: qualquer nome X-* (exceto X-SES-* e X-Ritto-Mail-*) mais In-Reply-To, References, Importance, Priority, Comments, Keywords, Organization e o par de descadastro em um clique — List-Unsubscribe (um ou mais alvos <https://…> ou <mailto:…>) com List-Unsubscribe-Post (List-Unsubscribe=One-Click); qualquer outro é 422. Os dois vêm juntos, e List-Unsubscribe precisa de um alvo https. Em um envio com topic_id, o par que você informa substitui o gerado: os pedidos de um clique passam a chegar no seu endpoint, o Ritto Mail não registra opt-out por eles, e um placeholder {{{UNSUBSCRIBE_URL}}} no corpo continua apontando para a página do Ritto Mail.
  • Um envio em que todos os destinatários de to estão na lista de supressão ou saíram do topic_id é recusado com 422 all_recipients_suppressed (mensagem All recipients are suppressed); destinatários removidos de um envio que ainda tem alguém são simplesmente omitidos.
  • to, cc e bcc juntos não podem passar de 50 destinatários, e cada endereço precisa ser uma única caixa postal — um nome de exibição contendo @ é rejeitado, e endereços aceitos voltam na forma canônica Nome <usuario@host>.
  • Qualquer coisa não suportada é rejeitada com 422 em vez de descartada em silêncio (ex.: tls na atualização de domínio).

Erros

Erros usam o formato do Resend:

{ "statusCode": 422, "name": "validation_error", "message": "..." }

Idempotência

POST /emails e POST /emails/batch aceitam um header Idempotency-Key. Repetir com a mesma chave e o mesmo payload retorna a resposta original em vez de enviar de novo; a mesma chave com payload diferente retorna 409.

Paginação

As listagens trazem os itens do mais recente para o mais antigo (pela data de criação, como na Resend). Aceitam limit (1–100, padrão 20) e cursores after / before carregando o id de um item de uma página anterior: after (o último id de uma página) busca os próximos itens, mais antigos; before (o primeiro id de uma página) busca os anteriores, mais recentes. As respostas incluem has_more.

Nesta página