Referência para developers

API StrongX

Envie SMS, Email e WhatsApp para os seus clientes em Angola com uma única API REST. OTPs, confirmações de pedido, alertas e campanhas em massa.

Cada pedido de envio é aceite de imediato com o estado queued e processado de forma assíncrona. Quando o estado muda (sent, delivered, failed), a StrongX notifica o seu backend com um webhook assinado.

Um fluxo, totalmente assíncrono. Envie o pedido, guarde o messageId devolvido e acompanhe o resultado pelos webhooks ou pelo painel.

Começar

Base URL

Produção e sandbox usam o mesmo host. É a chave API que decide o ambiente: uma chave strx_… envia de verdade; uma chave strx_test_… simula o envio.

POSThttps://api.strongx.it.ao/v1/sms/send
Endpoint
https://api.strongx.it.ao/v1

Começar

Autenticação

Todas as chamadas exigem HTTPS e uma chave API no cabeçalho Authorization com o esquema Bearer. Associe a chave a uma aplicação aprovada para enviar com o nome e os remetentes dessa aplicação.

Crie e revogue chaves na secção Developer do painel. A chave completa só é mostrada uma vez.
Cabeçalho Authorization
Authorization: Bearer strx_YOUR_API_KEY

Testes

Sandbox

Com uma chave sandbox (strx_test_…) nada é cobrado e nenhuma mensagem sai para a operadora. Apenas os destinatários de teste abaixo são aceites; cada um simula um resultado. Webhooks, validações e formato das respostas são iguais aos de produção: o envio responde sempre 202 queued e o resultado do cenário chega depois, por webhook ou em GET /v1/messages/{id}.

CenárioDestinatárioNotas
Entregue
+244900000000
delivered@sandbox.strongx.ao
Passa por sent e delivered; dispara message.delivered.
Falha
+244900000001
bounce@sandbox.strongx.ao
Rejeitada pelo provider simulado; dispara message.failed.
Só enviado
+244900000002
sent@sandbox.strongx.ao
Fica em sent, sem confirmação de entrega.

Chaves sandbox funcionam mesmo antes de a aplicação ser aprovada, mas só nos endpoints de envio. Outros endpoints respondem 403 sandbox_not_supported. Qualquer outro destinatário responde 422 sandbox_recipient_not_allowed.

Experimente no sandbox
# Use a SANDBOX key (strx_test_…). Nothing is charged or sent.
curl -X POST https://api.strongx.it.ao/v1/sms/send \
  -H "Authorization: Bearer strx_test_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "to": "+244900000000", "message": "Hello sandbox" }'

# +244900000000  → delivered
# +244900000001  → failed
# +244900000002  → sent (no delivery receipt)

Mensagens

Enviar SMS

POST/v1/sms/send

Envia um SMS para um número. Use message para texto livre ou templateId + variables.

Corpo do pedido

CampoTipoDescrição
to
obrigatório
stringNúmero do destinatário, ex.: +244923456789.
message
opcional
stringTexto da mensagem (máx. 1600).
applicationId
opcional
uuidAplicação que envia. Por omissão, a aplicação associada à chave.
templateId
opcional
uuidTemplate a usar em vez do texto livre.
variables
opcional
objectValores para as variáveis do template, ex.: { "name": "Ana" }.
curl -X POST https://api.strongx.it.ao/v1/sms/send \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+244923456789",
    "message": "Hello from StrongX!",
    "applicationId": "YOUR_APP_ID"
  }'
Resposta
{
  "success": true,
  "data": {
    "messageId": "7d1c2f9e-5b1a-4c6e-9a43-0f8f2b6d1e21",
    "status": "queued"
  }
}

Experimentar no sandbox

Cenário

Mensagens

SMS em massa

POST/v1/sms/send-bulk

Envia o mesmo SMS para até 500 números, com {{name}} personalizado por destinatário. O custo é debitado de uma só vez.

Corpo do pedido

CampoTipoDescrição
recipients
obrigatório
arrayLista de { phone, name? } (1–500).
message
opcional
stringTexto da mensagem; aceita {{name}}.
applicationId
opcional
uuidAplicação que envia. Por omissão, a aplicação associada à chave.
templateId
opcional
uuidTemplate a usar em vez do texto livre.
curl -X POST https://api.strongx.it.ao/v1/sms/send-bulk \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": [
      { "phone": "+244923456789", "name": "João" },
      { "phone": "+244912345678", "name": "Maria" }
    ],
    "message": "Hello from StrongX!",
    "applicationId": "YOUR_APP_ID"
  }'
Resposta
{
  "success": true,
  "data": {
    "enqueued": 2,
    "totalCost": 10.0,
    "messages": [
      { "messageId": "…", "phone": "244923456789", "status": "queued" },
      { "messageId": "…", "phone": "244912345678", "status": "queued" }
    ]
  }
}

Experimentar no sandbox

Mensagens

Enviar Email

POST/v1/email/send

Envia um email. O HTML é sanitizado antes do envio.

Corpo do pedido

CampoTipoDescrição
to
obrigatório
stringEmail do destinatário.
subject
opcional
stringAssunto (máx. 500). Obrigatório sem template.
htmlBody
opcional
stringCorpo HTML. Obrigatório sem template.
textBody
opcional
stringVersão em texto simples.
senderId
opcional
uuidRemetente verificado da aplicação (domínio próprio). Sem ele, usa o remetente da plataforma.
applicationId
opcional
uuidAplicação que envia. Por omissão, a aplicação associada à chave.
templateId
opcional
uuidTemplate a usar em vez do texto livre.
variables
opcional
objectValores para as variáveis do template, ex.: { "name": "Ana" }.
attachments
opcional
arrayLista de { url, filename, contentType }.
curl -X POST https://api.strongx.it.ao/v1/email/send \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "user@example.com",
    "subject": "Hello from StrongX!",
    "htmlBody": "<h1>Hello!</h1><p>This is a test email.</p>",
    "textBody": "Hello! This is a test email.",
    "applicationId": "YOUR_APP_ID"
  }'
Resposta
{
  "success": true,
  "data": {
    "messageId": "7d1c2f9e-5b1a-4c6e-9a43-0f8f2b6d1e21",
    "status": "queued"
  }
}

Experimentar no sandbox

Cenário

Mensagens

Email em massa

POST/v1/email/send-bulk

Envia o mesmo email para até 500 destinatários.

Corpo do pedido

CampoTipoDescrição
recipients
obrigatório
string[]Lista de emails (1–500).
subject
opcional
stringAssunto (máx. 500). Obrigatório sem template.
htmlBody
opcional
stringCorpo HTML. Obrigatório sem template.
textBody
opcional
stringVersão em texto simples.
senderId
opcional
uuidRemetente verificado da aplicação (domínio próprio). Sem ele, usa o remetente da plataforma.
applicationId
opcional
uuidAplicação que envia. Por omissão, a aplicação associada à chave.
templateId
opcional
uuidTemplate a usar em vez do texto livre.
attachments
opcional
arrayLista de { url, filename, contentType }.
curl -X POST https://api.strongx.it.ao/v1/email/send-bulk \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": ["user1@example.com", "user2@example.com"],
    "subject": "Hello from StrongX!",
    "htmlBody": "<h1>Hello!</h1><p>This is a bulk email.</p>",
    "applicationId": "YOUR_APP_ID"
  }'
Resposta
{
  "success": true,
  "data": {
    "sent": 2,
    "failed": 0,
    "messages": [
      { "messageId": "…", "email": "ana@example.com", "status": "queued" },
      { "messageId": "…", "email": "rui@example.com", "status": "queued" }
    ]
  }
}

Experimentar no sandbox

Mensagens

Enviar WhatsApp

POST/v1/whatsapp/send

Envia uma mensagem WhatsApp. Fora da janela de 24h use um template aprovado (templateId).

Corpo do pedido

CampoTipoDescrição
to
obrigatório
stringNúmero com indicativo, ex.: +244923456789.
message
opcional
stringTexto (máx. 4096). Obrigatório sem template.
applicationId
opcional
uuidAplicação que envia. Por omissão, a aplicação associada à chave.
templateId
opcional
uuidTemplate a usar em vez do texto livre.
variables
opcional
objectValores para as variáveis do template, ex.: { "name": "Ana" }.
attachments
opcional
arrayLista de { url, filename, contentType }.
curl -X POST https://api.strongx.it.ao/v1/whatsapp/send \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "to": "+244923456789",
    "message": "Hello from StrongX via WhatsApp!",
    "applicationId": "YOUR_APP_ID"
  }'
Resposta
{
  "success": true,
  "data": {
    "messageId": "7d1c2f9e-5b1a-4c6e-9a43-0f8f2b6d1e21",
    "status": "queued"
  }
}

Experimentar no sandbox

Cenário

Mensagens

Campanhas

Uma campanha junta contactos, um segmento e um template, e envia para todos de uma vez pelo mesmo caminho do envio em massa. Os passos abaixo mostram o fluxo completo.

Contactos, segmentos, templates e campanhas exigem uma chave de produção. Chaves sandbox recebem 403 sandbox_not_supported.

1. Criar um contacto

POST/v1/contacts
curl -X POST https://api.strongx.it.ao/v1/contacts \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "João Silva",
    "phone": "+244923456789",
    "email": "joao@example.com"
  }'
# Response: {"success": true, "data": {"id": "...", ...}}

2. Criar um segmento

POST/v1/segments
curl -X POST https://api.strongx.it.ao/v1/segments \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Clientes VIP",
    "description": "Clientes com maior volume de compras"
  }'
# Response: {"success": true, "data": {"id": "...", ...}}

3. Adicionar contactos ao segmento

POST/v1/segments/{segmentId}/contacts
curl -X POST https://api.strongx.it.ao/v1/segments/YOUR_SEGMENT_ID/contacts \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "contact_ids": ["YOUR_CONTACT_ID"]
  }'
# Note: this endpoint takes "contact_ids" in snake_case (an exception
# to the camelCase convention used by the rest of the API).

4. Criar um template

POST/v1/templates
curl -X POST https://api.strongx.it.ao/v1/templates \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "channel": "sms",
    "name": "Promoção de aniversário",
    "body": "Olá {{name}}, tens um desconto especial à tua espera!",
    "variables": ["name"]
  }'
# Response: {"success": true, "data": {"id": "...", ...}}

5. Criar a campanha

POST/v1/campaigns
curl -X POST https://api.strongx.it.ao/v1/campaigns \
  -H "Authorization: Bearer strx_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Campanha de aniversário",
    "channel": "sms",
    "segmentId": "YOUR_SEGMENT_ID",
    "templateId": "YOUR_TEMPLATE_ID"
  }'
# Response: {"success": true, "data": {"id": "...", "status": "draft", ...}}

6. Disparar a campanha

POST/v1/campaigns/{campaignId}/send
curl -X POST https://api.strongx.it.ao/v1/campaigns/YOUR_CAMPAIGN_ID/send \
  -H "Authorization: Bearer strx_YOUR_API_KEY"
# Queues the send for every contact in the segment through the same bulk
# path as /send-bulk (credits, rate limits and provider resolution behave
# the same way).

Webhooks

Eventos de estado

Registe um URL de webhook na aplicação (painel → Aplicações → Webhooks). A cada mudança de estado, a StrongX faz POST ao seu URL com o corpo { "event", "data" }. Responda com 2xx; outros códigos são repetidos mais tarde.

EventoDescrição
message.sentA operadora/provider aceitou a mensagem.
message.deliveredEntrega confirmada ao destinatário.
message.failedA mensagem falhou; o custo é devolvido se nenhum provider a aceitou.
{
  "event": "message.delivered",
  "data": {
    "message_id": "7d1c2f9e-5b1a-4c6e-9a43-0f8f2b6d1e21",
    "channel": "sms",
    "status": "delivered",
    "to": "244923456789",
    "provider_name": "telco_sms",
    "error_message": null,
    "sandbox": false
  }
}

Webhooks

Verificar assinatura

Cada webhook é assinado com o segredo da subscrição. Use X-StrongX-Signature-V2: calcule o HMAC-SHA256 de timestamp + "." + corpo bruto e compare com v1. Rejeite pedidos com t demasiado antigo para evitar replays.

v1 = HexEncode( HMAC-SHA256( secret, t + "." + rawBody ) )

X-StrongX-Signature (sha256=<hex>, HMAC do corpo bruto) continua a ser enviado para compatibilidade.

Verificação (Node.js)
import crypto from 'node:crypto';

// rawBody: the request body exactly as received (Buffer)
function verifyStrongX(rawBody, header, secret, toleranceSec = 300) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const timestamp = Number(parts.t);
  if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > toleranceSec) return false;

  const expected = crypto
    .createHmac('sha256', secret)
    .update(`${parts.t}.`)
    .update(rawBody)
    .digest('hex');

  return crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(parts.v1 ?? ''));
}

// verifyStrongX(req.rawBody, req.get('X-StrongX-Signature-V2'), process.env.STRONGX_WEBHOOK_SECRET)

Referência

Consultar mensagem

GET/v1/messages/{messageId}

Devolve uma mensagem de qualquer canal com o estado atual. Use para acompanhar o resultado depois do envio, quando não usa webhooks. Funciona com chaves sandbox (só para mensagens sandbox).

Resposta
{
  "success": true,
  "data": {
    "id": "7d1c2f9e-5b1a-4c6e-9a43-0f8f2b6d1e21",
    "channel": "sms",
    "to": "244900000001",
    "status": "failed",
    "errorMessage": "Sandbox: simulated provider rejection",
    "cost": 0.0,
    "isSandbox": true,
    "createdAt": "2026-10-08T10:00:00+00:00",
    "updatedAt": "2026-10-08T10:00:01+00:00"
  }
}

Referência

Estados da mensagem

EstadoSignificado
queuedAceite pela StrongX e à espera de envio.
sentEntregue à operadora/provider.
deliveredEntrega confirmada.
failedNão foi possível enviar. Veja errorMessage.

Referência

Erros

Erros devolvem um código HTTP e um corpo JSON com error (código estável) e message (texto legível).

CódigoSignificado
401Chave em falta, inválida ou aplicação não aprovada.
402Saldo insuficiente na carteira ou na reserva da aplicação.
403Sem permissão (por exemplo, chave sandbox fora dos endpoints de envio).
404Recurso não encontrado.
422Pedido inválido (campos em falta, destinatário sandbox não permitido…).
429Limite de pedidos excedido; tente novamente em instantes.
422
{
  "error": "sandbox_recipient_not_allowed",
  "message": "Sandbox keys only accept test recipients: …"
}

Referência

Limites

  • SMS: até 10 pedidos por segundo por conta.
  • Envios em massa: até 500 destinatários por pedido.
  • SMS: até 1600 caracteres; WhatsApp: até 4096 caracteres.