/create-message-v4
API de Mensagem — v4 (createMessage)
Documentação do módulo createMessage, que cria uma mensagem (push, SMS, WhatsApp, e-mail, RCS, in-app, on-site ou multicanal), persistindo um documento control_message no MongoDB e os destinatários no MariaDB. Suporta agendamento, envio imediato (instant_message), campanhas, templates de API e fluxo de aprovação.
Gerada a partir do código em 2026-07-07 (branch
marco).
| Endpoint | O que faz |
|---|---|
POST /v4/createMessage/ | Cria e agenda (ou dispara na hora) uma mensagem multicanal |
Autenticação
app_tokenobrigatório no corpo — resolvido no MariaDB (app); inválido → 401.- JWT condicional: se o app tiver token ativo em
app_auth_token, o headerAuthorizationpassa a ser obrigatório (ausente ou"undefined"→ 403). Se o app não tem JWT ativo, o header é ignorado.
Envelopes aceitos
| Formato | Comportamento |
|---|---|
{ "savePushRequest": { ... } } | usa o objeto interno |
{ "sendPushRequest": { ... } } | formato V1: renomeia identifier→identifiers (força array), message→body, e força instant_message = true |
| objeto direto | sem envelope |
Corpo da requisição
Apenas app_token é obrigatório no schema ("app_token is required"); todo o resto é opcional/nullish — as obrigatoriedades condicionais são validadas no service (abaixo). Campos extras são descartados (.strip()). Validação Zod retorna apenas a primeira mensagem de erro.
Conteúdo da mensagem
| Campo | Tipo | Obs. |
|---|---|---|
title | string | default "" |
body | string | default ""; pode vir de campanha/template; no V1 é message |
image | string | gravado como img_push |
url, url_type | string | url vira url_push |
actions | any | ações do push |
email | objeto | html, subjectEmail, contentHeaderEmail, sender_email, sender_name, reply_to_* |
wtp_data | objeto | WhatsApp Template (template_id, params, buttonParam...) |
rcs_data | objeto | RCS (type: CAROUSEL/RICHCARD/..., contents[], title, description, image_url) |
inapp | objeto | in-app (title, body) |
on_site_message | objeto | on-site (title, body, scratch_card.sortition, wellcomeCampaign) |
Destinatários (mutuamente exclusivos entre si)
| Campo | Tipo | Obs. |
|---|---|---|
identifiers | string | string[] | no V1 é identifier |
audiences | (number | string)[] | exatamente uma audiência, inteiro positivo, pertencente ao app |
registration | string | token de device |
subscriber_id | string | string[] | |
phone_number | string | number | normalizado (remove não-dígitos; prefixa 55 em celular BR de 10–11 dígitos) |
subscriber_email | string |
Canal, agendamento e fluxo
| Campo | Tipo | Obs. |
|---|---|---|
channel_id | number | string | default 1 (push) |
channel_flag | number | string | flag multicanal; 0 → null |
channels | array | objeto | array (novo padrão) ou objeto por nome (legado); cada canal exige custom_body |
instant_message | boolean | string | truthy = true/"true"/1/"1"; exige destinatário direto |
schedule | string | data de agendamento, convertida para o timezone do app; ausente = agora |
send_until, expiration_time | string | validade; on-site sem send_until ganha default +72h |
expiration_period + expiration_period_type | number/string + string | hours/days/minutes |
need_approval | boolean | number | truthy → mensagem criada com status pendente (11) |
campaign | number | string | ID em new_campaigns; preenche conteúdo/canais da campanha |
template_id / api_template_id | number | string | dispara fluxo de template de API |
tags | objeto | valores para substituição de {{tag}} no template |
automation_id | number | string | gravado no doc; suprime sender_id |
sender_id | number | string | ignorado se houver automation_id |
origin | number | string | default 3 (vira message_type_id); 4 = bulk |
authentication_code | string | 2FA: com phone_number, grava em message_authentication |
utm_source/utm_medium/utm_campaign/utm_term, utm_data | string / objeto | |
additional_data | any | gravado como meta_data |
geo_fence, first_access, af, email_test, is_test | diversos | is_test é aceito mas não usado no insert |
Validações condicionais (service) — mensagens exatas
- Faltando token/destinatário/corpo →
"Required parameters were not informed: <lista>."(corpo não é exigido se houvertemplate_id/api_template_id/campaign). campaignjunto comtemplate_id→"campaign e template_id são mutuamente exclusivos. Envie apenas um."- Mais de um tipo de destinatário →
"You must choose between an audience, an identifier, a registration or subscriberID." instant_messagesem destinatário direto →"instant_message requires a direct recipient (identifiers, registration, subscriber_id, phone_number or subscriber_email)."- Audiência inválida →
"Invalid audience: exactly one audience is required."/"Invalid audience_id: <valor>"/"Invalid audience: <id> does not belong to app <appId>." - Campanha inexistente →
"Invalid campaign ID!"· Canal semcustom_body→"Invalid payload. Check your JSON. [custom_body] is required"
Comportamento
- Template (
template_idsemcampaign): delega ao fluxo de template de API (new_api_template), que valida as{{tags}}e reexecuta a criação uma vez por identifier, sempre comoinstant_message. Erros próprios de tags (tag não cadastrada, obrigatória ausente, template inexistente). - Campanha (
campaign): lênew_campaigns/new_campaign_channele preenche título/corpo/imagem/canais (inclui multicanal por prioridade viamultichannel_config). - Persistência: insere o documento em
inn_db.control_messagecomschema_version: 2, status inicial11(pendente) seneed_approval, senão0. Canais são adicionados via$addToSetno arraychannel, sempre no shape único{ channel: { channel_provider_id, priority, custom_title, custom_body, ... } }. - Destinatários (MariaDB
control_message_recipient): gravados por tipo — identifier=1, subscriber=5, phone=6, email=7, registration=8. Depois o status da CM vai para1(pronta). - Dispatch:
instant_message: chama in-process oprocessQueuedo módulonewQueuePubsubV2(fire-and-forget), que cria tópico/assinatura Pub/Sub por CM e despacha. Se pendente de aprovação, não despacha.- Não-instant (agendada): fica em status
1e é coletada depois pelo agendador — não passa pelo dispatch deste módulo. - Falha ao salvar destinatários/dispatch → status
9(erro).
- Aprovação: com
need_approval, dispara e-mail para os aprovadores (app_approval_email) via self-call HTTP interno (fire-and-forget).
Importante: esta API não verifica existência/atividade do subscriber — a checagem é responsabilidade do fluxo de entrega.
Respostas
Shape sempre { "saveResponse": { "status": <n>, "details": <...> } }.
Sucesso — 200. O details varia por fluxo:
| Fluxo | details |
|---|---|
| instant | { "CM_id": "<id>", "message": "Message created and directed to the delivery queue." } ou "Message created and pending approval." |
| identifiers | { "control": "<id>", "recipients": <total> } |
| audience | { "control": "<id>", "Audiences": [<id>] } |
| subscriber_id | { "control": "<id>", "recipients": [...] } |
bulk (origin: 4) | { "control": "<id>", "recipients": <identifiers> } |
| fallback "all" | { "control": "<id>", "recipients": "all" } |
| template | resultado único ou array (um por identifier) |
Erros:
| Status | Quando | details |
|---|---|---|
| 400 | validação Zod, payload vazio, app_token ausente ou ValidationError | mensagem do erro (ex.: "Invalid payload. Check your JSON.", "app_token is required.") |
| 401 | app_token inválido | "Invalid App Token." |
| 403 | app com JWT ativo sem header Authorization | "Forbidden, check your authorization!" |
| 500 | DomainError ou erro inesperado | mensagem do erro ou "Internal Server Error" |
Exemplos
Push agendado para lista de identifiers:
{
"app_token": "a1b2c3d4e5f6",
"title": "Promoção relâmpago",
"body": "Aproveite 30% OFF só hoje!",
"image": "https://cdn.exemplo.com/promo.png",
"url": "https://loja.exemplo.com/ofertas",
"channel_id": 1,
"identifiers": ["user-123", "user-456"],
"schedule": "2026-07-08 09:00:00",
"expiration_period": 24,
"expiration_period_type": "hours",
"utm_source": "push"
}Envio instant de 2FA por SMS:
{
"app_token": "a1b2c3d4e5f6",
"body": "Seu código de acesso é 4821",
"instant_message": true,
"phone_number": "+55 11 99999-8888",
"authentication_code": "4821",
"channel_id": 2
}Formato V1 (legado):
{
"sendPushRequest": {
"app_token": "a1b2c3d4e5f6",
"identifier": "user-123",
"title": "Olá",
"message": "Bem-vindo de volta!"
}
}Referências de código
- Router:
v4/createMessage/routes/createMessageRoute.js - Validator:
v4/createMessage/validators/createMessageSchema.js(schema, adaptador V1 e middleware) - Controller:
v4/createMessage/controller/createMessageController.js - Services:
v4/createMessage/services/createMessageService.js,v4/createMessage/services/apiTemplateService.js - Repositórios:
controlMessageRepository.js(MongoDBcontrol_message),messageLogRepository.js(MariaDBcontrol_message_recipient,message_authentication),appRepository.js(MariaDB) - Dispatch delegado a
v4/newQueuePubsubV2/services/queueOrchestrationService.js
Updated 12 days ago
