Pular para o conteúdo principal

E-mails transacionais

Um e-mail transacional é o que o seu sistema dispara para uma pessoa por causa de algo que ela fez: a troca de senha, o código de acesso, a abertura de um ticket. O Workfuse recebe o pedido com o mesmo corpo e a mesma resposta do envio único transacional do HubSpot (versão 2026-09), monta o e-mail com o modelo da instituição e o envia pela conta de envio dela, no pool transacional, sem link de descadastro.

O sufixo dos caminhos é o do HubSpot, sob API_BASE/public/v1/crm. Quem já integra com o HubSpot troca três coisas: a base da URL, a chave e o emailId de cada modelo.

POST /crm/marketing/transactional/2026-09/single-email/send → 200 PENDING
o Workfuse confere bounce e spam, monta o modelo e envia
GET /crm/marketing/v3/email/send-statuses/{statusId} → 200 COMPLETE · SENT

Antes de enviar​

  • A instituição precisa estar ligada. O módulo crm.transactionalEmail precisa estar ativo na organização; sem ele, o pedido recebe 403. A equipe Workfuse liga o envio transacional na conta de envio da instituição (pool transacional e domínios de remetente permitidos); sem isso, o pedido recebe 422.
  • O modelo e o código dele. A instituição cria o modelo em CRM › Comunicação › E-mail › Modelos, com assunto, corpo e, se quiser, o remetente. Na edição do modelo aparece o Código para a API: é o número que vai no emailId.
  • A credencial. Um token de conta de serviço (wfs_...) com a permissão integration.public-crm.use e a superfície de API pública, ou uma API key com o módulo crm. Ela vai no cabeçalho Authorization: Bearer, como você já manda ao HubSpot, e define a instituição.

Enviar​

POST /marketing/transactional/2026-09/single-email/send

curl -X POST "API_BASE/public/v1/crm/marketing/transactional/2026-09/single-email/send" \
-H "Authorization: Bearer wfs_seu_token_aqui" \
-H "Content-Type: application/json" \
-d '{
"emailId": 1042,
"message": { "to": "ana@exemplo.com", "sendId": "reset-123" },
"customProperties": { "reset_link": "https://exemplo.com/reset?t=abc" }
}'
CampoO que é
emailIdO código do modelo, inteiro (texto só de dígitos também vale)
message.toO destinatário: "Nome <e-mail>" ou o e-mail. Só o endereço é usado; o nome não vai no e-mail
message.fromOpcional. "Nome <e-mail>" ou o e-mail; o domínio precisa estar entre os permitidos da conta. Sem ele, vale o remetente do modelo e, por fim, o padrão da conta
message.sendIdOpcional. O mesmo identificador gera um e-mail só
message.replyTo, message.cc, message.bccOpcionais, até 10 endereços cada
contactPropertiesValores de contato que o modelo usa (firstname, ...)
customPropertiesOs valores do pedido (reset_link, número do ticket, ...)

A resposta é a EmailSendStatusView do HubSpot:

{ "statusId": "cmt9envio", "status": "PENDING", "requestedAt": "2026-10-16T12:00:00.000Z" }

Recusa sem erro HTTP. Como no HubSpot, um modelo inexistente, um destinatário ou remetente inválido, um valor faltando ou um identificador reaproveitado respondem 200 com o envio já concluído e o resultado:

{ "statusId": "cmt9outro", "status": "COMPLETE", "sendResult": "MISSING_TEMPLATE_PROPERTIES",
"message": "Faltam valores de campos que o modelo usa e que não têm padrão.",
"requestedAt": "2026-10-16T12:01:00.000Z", "completedAt": "2026-10-16T12:01:00.000Z" }
sendResultQuando
SENTO provedor aceitou o e-mail
MISSING_CONTENTO código não é de um modelo desta instituição, ou o modelo está sem conteúdo ou assunto
MISSING_TEMPLATE_PROPERTIESUm campo do pedido (custom.*) sem valor e sem padrão
INVALID_TO_ADDRESSDestinatário inválido
INVALID_FROM_ADDRESSRemetente inválido ou fora dos domínios permitidos
IDEMPOTENT_FAILO sendId já foi usado com outro modelo ou destinatário; nenhum e-mail sai
PREVIOUSLY_BOUNCED, PREVIOUS_SPAMO endereço teve bounce permanente ou denunciou spam antes
PORTAL_SUSPENDEDO envio transacional foi desligado depois do pedido
UNDELIVERABLEO provedor descartou o e-mail

O schema declara os 51 valores do HubSpot; os de cima são os que o Workfuse produz.

O mesmo identificador. O mesmo sendId com o mesmo modelo e destinatário devolve o envio original, sem segundo e-mail.

Consultar​

GET /marketing/v3/email/send-statuses/{statusId} devolve a mesma EmailSendStatusView, com eventId quando o e-mail saiu. Só a credencial da própria instituição enxerga o envio; outra recebe 404.

Erros​

Toda recusa HTTP vem no corpo Error do HubSpot: message, correlationId, category e, quando há, subCategory e errors[] com o campo em in.

HTTPcategoryQuando
400VALIDATION_ERRORCorpo fora da forma: emailId ou to faltando, tipo ou tamanho errado
401INVALID_AUTHENTICATIONCredencial ausente ou inválida
403MISSING_SCOPESSem o módulo ou a permissão, ou crm.transactionalEmail desligado
404OBJECT_NOT_FOUNDEnvio de outra instituição ou inexistente (consulta)
422VALIDATION_ERROREnvio transacional desligado na instituição (TRANSACTIONAL_EMAIL_NOT_ENABLED)
429RATE_LIMITSMais de 120 pedidos por minuto no token; respeite o Retry-After

Os campos do modelo​

O modelo aceita a sintaxe do HubSpot:

  • {{ custom.reset_link }} — o valor de customProperties.
  • {{ contact.firstname }} — de contactProperties, senão do contato da instituição com o mesmo e-mail (firstname é a primeira palavra do nome).
  • {{ personalization_token('contact.firstname','Aluno') }} — com padrão.

Listas e objetos em customProperties são aceitos, mas o modelo não os lê, como no HubSpot. Os valores do pedido são apagados quando o envio termina.

Se você vem do HubSpot​

  • O Workfuse não cria nem altera contato. O envio se liga ao contato que já existe com o mesmo e-mail na instituição; contactProperties só alimenta o modelo.
  • O descadastro de marketing não bloqueia o e-mail transacional; bounce permanente e denúncia de spam bloqueiam.
  • Troque a base, a chave e o emailId. O resto do corpo e da resposta é o mesmo.