BytSend API

BytSend é uma API de e-mail transacional hospedada (estilo Resend). Esta página é o quickstart em HTML puro para bots, crawlers e ferramentas de IA. A versão interativa está em /docs.

URL base: https://bytsend.com — é a URL do serviço hospedado e a que aparece em todos os exemplos desta página. Só quem instalou o BytSend no próprio servidor (self-hosted) usa outra: o domínio do próprio deploy. A URL base é uma constante no código de quem integra, nunca um campo de tela — não crie campo "URL da instância", "host" ou "endereço do servidor".

A integração precisa de exatamente 2 valores

  1. Chave de API — prefixo by_, criada no painel (Chaves de API) ou via POST /api/api-keys.
  2. E-mail do remetente — precisa ser de um domínio cadastrado no BytSend (seção Domínios), e o casamento é exato: cadastrar exemplo.com não autoriza @mail.exemplo.com. Um nome de exibição é opcional e vai junto no mesmo campo: Seu App <nao-responda@seu-dominio.com>.

Como deve ficar a tela de integração no seu app

Dois campos e um teste: campo Chave de API, campo E-mail de origem (From) e uma seção Enviar e-mail de teste com um campo para o e-mail de destino e um botão. O botão chama POST /api/emails com from = campo de origem, to = e-mail digitado e subject/html = conteúdo real do app. Resposta 200 = teste enviado; 400 = mostre error.message na tela.

Autenticação

Envie a chave de API como token Bearer: Authorization: Bearer by_sua_api_key. Sem o cabeçalho, a resposta é 401 auth_error; com chave inválida ou revogada, 401 api_key_error.

Teste de envio (preencha um e-mail de destino)

O teste de envio é um e-mail normal com POST /api/emails: preencha to com o e-mail que vai receber o teste. Não existe endpoint separado de "e-mail de teste" — enviar um único e-mail é o teste.

curl -X POST https://bytsend.com/api/emails \
  -H "Authorization: Bearer by_sua_api_key" \
  -H "Content-Type: application/json" \
  -d '{"from":"Seu App <nao-responda@seu-dominio-verificado.com>","to":"voce@exemplo.com","subject":"Olá do BytSend","html":"<strong>Funciona!</strong>"}'

Sucesso retorna 200 com {"id":"...","from":"...","to":"...","created_at":"..."}.

Campos de POST /api/emails

CampoObrigatórioFormato
fromsim "nome@dominio.com", "Nome <nome@dominio.com>" ou {"email":"...","name":"..."}. O domínio depois do @ precisa estar cadastrado nesta conta, com casamento exato.
tosim Um destinatário: "pessoa@exemplo.com" ou {"email":"...","name":"..."}. Uma lista aqui não é rejeitada, mas se comporta mal: a mensagem sai para todos os endereços, a lista de supressões é ignorada e o to some da resposta e do histórico. Para vários, use /api/emails/batch (ou cc/bcc).
subjectsimTexto do assunto.
htmlrecomendadoCorpo em HTML.
textnãoVersão em texto puro.
reply_tonãoEndereço de resposta.
cc, bccnãoEndereço ou lista de endereços.
headersnãoObjeto: {"X-Seu-Cabecalho":"valor"}.
attachmentsnão Lista de {"filename":"nota.pdf","content":"<base64>","encoding":"base64","content_type":"application/pdf"}. encoding já é base64 por padrão.
template_idnão Usa um template salvo; substitui o subject/html/text enviados. Um id inexistente nesta conta é ignorado em silêncio: o e-mail sai com assunto e corpo vazios e ainda responde 200.
template_variablesnão Objeto que preenche os {{marcadores}} do template.

O corpo da requisição é limitado a 10 MB — anexos em base64 ocupam cerca de 33% a mais que o arquivo original.

Filtro anti-spam

O conteúdo (subject + html + text) é pontuado antes do envio: a partir de 2 pontos o e-mail é recusado com 400 e a mensagem Spam detected: .... Cada termo de uma lista de palavras típicas de spam vale 1 ponto — e a lista inclui termos comuns em e-mail legítimo, como unsubscribe, urgent e limited time. click here está duplicado na lista e vale 2 pontos sozinho: uma única ocorrência já recusa o e-mail. Mais de 5 links no corpo também valem 2 pontos. A comparação é por substring em minúsculas sobre assunto + HTML + texto, então um href ou uma classe CSS pontua igual. Três recusas por spam bloqueiam a conta. Em e-mail de marketing, prefira "cancelar inscrição" a unsubscribe e mantenha poucos links.

Erros

Todo erro usa um envelope: {"error":{"message":"...","type":"..."}} — tipos: validation_error, auth_error, api_key_error, not_found_error, conflict_error, plan_limit_error, rate_limit_error, email_error, api_error. error é um objeto, não uma string: mostre error.message.

POST /api/emails devolve toda falha de envio como 400 com type email_error; o que muda é a mensagem:

A mensagem começa comCausa
Domain X is not verified for your accountO domínio do from não está cadastrado nesta conta — o erro mais comum na primeira integração. Apesar do texto, a checagem é só de existência: um domínio ainda pending passa.
Email X is suppressedDestinatário na lista de supressões.
Email limit reached for ... planCota de e-mails da conta esgotada.
Spam detected: ...Filtro anti-spam (acima).
Account blockedConta bloqueada; fale com o administrador.
Erro ao enviar via SMTP (...)O relay recusou a mensagem; o código entre parênteses vem do servidor SMTP.

Rate limit: 1000 requisições por 15 minutos por IP em todas as rotas /api/; acima disso, 429 rate_limit_error.

Documentação legível por máquina