Pular para o conteúdo
smsbulk

API de SMS em massa v1

Uma pequena API REST para enviar SMS em massa a partir do seu próprio software: JSON de entrada e saída, chaves Bearer, os mesmos preços e verificações do console, e webhooks assinados para relatórios de entrega. URL base https://smsbulk.cc/rest/v1

Visão geral

Envie para até 8,000 números por solicitação, cada um com seus próprios valores de mesclagem, e a API precifica cada destinatário com seu próprio texto mesclado, exatamente como o console. Solicite uma cotação primeiro com o mesmo corpo para saber o custo; nada é enviado ou cobrado por uma cotação. Os horários são ISO 8601 em UTC, o dinheiro é uma string em dólares americanos com cinco casas decimais.

curl https://smsbulk.cc/rest/v1/send \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "recipients": [
      { "to": "+14155550142", "fields": { "name": "Maria" } },
      { "to": "+447400123456", "fields": { "name": "Tom" } }
    ],
    "text": "Hi {{name}}, your order ships today.",
    "client_ref": "order-batch-17"
  }'

Autenticação

Crie uma chave no console em API e webhooks; as chaves são liberadas após a primeira recarga creditada. Envie-a em cada solicitação como um token Bearer. Uma chave é mostrada uma vez; você pode manter até 5 chaves e revogar qualquer uma delas de uma vez.

Authorization: Bearer smsb_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Tarifas

Público, sem necessidade de chave. O preço por segmento de SMS para cada destino, ou para um código ISO.

GEThttps://smsbulk.cc/rest/v1/rates

GEThttps://smsbulk.cc/rest/v1/rates/{ISO}

{
  "country": "US",
  "name": "United States",
  "dial_code": "+1",
  "rate": "0.00485",
  "currency": "USD",
  "per": "message segment"
}

Crédito

GEThttps://smsbulk.cc/rest/v1/credit

{ "credit": "125.40000", "currency": "USD", "account": "A418820037715" }

Cotação

Precisa um envio sem enviá-lo. Recebe o mesmo corpo que Enviar.

POSThttps://smsbulk.cc/rest/v1/quote

CampoSignificado
toUm número ou uma lista. Formato internacional com + é mais seguro; números locais precisam de default_country.
recipientsEm vez de to: uma lista de { to, fields } onde fields preenche campos de mesclagem como {{name}}.
textA mensagem, até 2,000 caracteres e 10 segmentos após a mesclagem.
default_countryCódigo ISO usado para números sem +, como GB. Usa o padrão salvo em Configurações.
opt_outAdiciona seu texto de cancelamento salvo como última linha (salve-o primeiro em Configurações).
{
  "recipients": 2,
  "messages": 2,
  "segments": { "min": 1, "max": 1 },
  "encoding": "GSM-7",
  "total": "0.01240",
  "currency": "USD",
  "credit": "125.40000",
  "credit_after": "125.38760",
  "countries": [
    { "country": "US", "recipients": 1, "rate": "0.00485", "segments": 1, "subtotal": "0.00485" },
    { "country": "GB", "recipients": 1, "rate": "0.00755", "segments": 1, "subtotal": "0.00755" }
  ],
  "left_out": []
}

Enviar

Cria uma campanha, retira o total do seu crédito e coloca as mensagens na fila. Responde com 201 e a campanha. Números que não podem ser enviados são listados em left_out e nunca são cobrados.

POSThttps://smsbulk.cc/rest/v1/send

CampoSignificado
to / recipients / text / default_country / opt_outComo em Quote.
send_atHorário ISO 8601 para início, de 5 minutos a 90 dias no futuro. Omita para enviar agora.
nameSeu rótulo para a campanha, até 80 caracteres.
client_refSua própria referência, até 64 caracteres, retornada em cada mensagem e webhook.
HTTP/1.1 201 Created
{
  "campaign": {
    "id": "C507318264409",
    "name": null,
    "status": "sending",
    "source": "api",
    "test": false,
    "recipients": 2,
    "cost": "0.01240",
    "refunded": "0.00000",
    "net_cost": "0.01240",
    "currency": "USD",
    "send_at": null,
    "created_at": "2026-11-07T14:02:11.000Z",
    "started_at": "2026-11-07T14:02:11.000Z",
    "finished_at": null,
    "client_ref": "order-batch-17"
  },
  "messages": 2,
  "left_out": []
}

Campanhas

GEThttps://smsbulk.cc/rest/v1/campaigns?limit=25&before={id}

GEThttps://smsbulk.cc/rest/v1/campaigns/{id}

GEThttps://smsbulk.cc/rest/v1/campaigns/{id}/messages?status=failed&limit=100&after={message id}

Uma única campanha inclui contagens por status: na fila, enviado, entregue, falhou e cancelado. Lista de mensagens com after e has_more; até 1.000 por página.

Mensagens

GEThttps://smsbulk.cc/rest/v1/messages/{id}

GEThttps://smsbulk.cc/rest/v1/messages?to=%2B14155550142&status=delivered&client_ref=order-batch-17&limit=50

{
  "id": "M220947781305",
  "campaign": "C507318264409",
  "to": "+14155550142",
  "country": "US",
  "segments": 1,
  "encoding": "GSM-7",
  "price": "0.00485",
  "status": "delivered",
  "reason": null,
  "reason_text": null,
  "refunded": false,
  "client_ref": "order-batch-17",
  "created_at": "2026-11-07T14:02:11.000Z",
  "sent_at": "2026-11-07T14:02:12.000Z",
  "finished_at": "2026-11-07T14:02:16.000Z"
}

Cancelar uma campanha agendada

POSThttps://smsbulk.cc/rest/v1/campaigns/{id}/cancel

Funciona até o horário de início. O custo total retorna ao seu crédito em uma linha do livro-razão e o status da campanha se torna cancelado.

Webhooks

Defina uma URL de endpoint no console. Enviamos JSON para message.delivered, message.failed e campaign.done, além de testar quando você pressiona Enviar evento de teste. Cada evento carrega quatro cabeçalhos, e qualquer resposta 2xx dentro de 10 segundos conta como recebida.

CampoSignificado
Smsbulk-EventNome do evento, como message.delivered.
Smsbulk-DeliveryID de entrega, o mesmo em cada tentativa de um evento.
Smsbulk-TimestampSegundos Unix quando esta tentativa foi assinada.
Smsbulk-Signaturesha256= seguido do HMAC-SHA256 em base64 do timestamp, uma quebra de linha e o corpo bruto, chaveado com seu segredo sbw_.

A entrega é tentada 8 vezes: imediatamente, depois de 1 minuto, 5 minutos, 15 minutos, 1 hora, 3 horas, 6 horas e 12 horas. Cada tentativa aparece no log de entrega do console com seu status HTTP e o início da sua resposta.

{
  "id": "dlv_3f9a1c07b2e44d58a6c1",
  "event": "message.failed",
  "created": "2026-11-07T14:02:16.000Z",
  "data": {
    "message": "M220947781305",
    "campaign": "C507318264409",
    "to": "+447400123456",
    "country": "GB",
    "status": "failed",
    "reason": "not_in_service",
    "segments": 1,
    "price": "0.00755",
    "client_ref": "order-batch-17"
  }
}

Verificar a assinatura

import crypto from "node:crypto";

// raw = the request body exactly as received (string), secret = your sbw_ signing secret
export function verify(raw, headers, secret) {
  const ts = headers["smsbulk-timestamp"];
  const want = "sha256=" + crypto.createHmac("sha256", secret).update(ts + "\n" + raw).digest("base64");
  const got = headers["smsbulk-signature"] || "";
  const fresh = Math.abs(Date.now() / 1000 - Number(ts)) < 300;
  return fresh && got.length === want.length && crypto.timingSafeEqual(Buffer.from(got), Buffer.from(want));
}

Erros e limites

Erros usam o status HTTP e um corpo JSON: {"error":{"code":"insufficient_credit","message":"..."}}. Nada é cobrado quando uma requisição falha.

CampoSignificado
400 bad_jsonO corpo não é JSON.
401 unauthorizedChave ausente, malformada ou revogada.
402 insufficient_creditO total excede seu saldo. Adicione créditos no console.
404 not_foundEndpoint, campanha, mensagem ou código ISO não encontrado nesta conta.
409 not_scheduledCancelamento solicitado para uma campanha já iniciada.
422 text_missing, text_too_long, too_many_segmentsMensagem vazia, com mais de 2,000 caracteres ou mais de 10 segmentos para um destinatário.
422 no_recipients, too_many, recipients_missingNenhum número válido, mais de 8,000 números, ou nem 'to' nem 'recipients' especificados.
422 schedule_range, bad_send_atsend_at fora do intervalo de 5 minutos a 90 dias, ou não é um horário válido.
422 opt_out_unsetopt_out está ativado, mas nenhum texto de cancelamento foi salvo nas Configurações.
429 rate_limitedMais de 300 solicitações por minuto para esta chave.

Cada resposta inclui X-RateLimit-Limit, X-RateLimit-Remaining e X-RateLimit-Reset.

Códigos excluídos

Números removidos antes da precificação retornam em left_out com sua posição na lista, o valor enviado, um código e o motivo claro.

CampoSignificado
no_country_codeSem '+' e sem país padrão definido.
too_short / too_longMenos de 8 ou mais de 15 dígitos.
not_a_numberLetras ou símbolos que não fazem parte de um número.
nanp_lengthUm número +1 sem onze dígitos.
not_coveredUm destino fora da nossa lista.
duplicateO mesmo número já apareceu anteriormente na solicitação.
suppressedO número está na sua lista de não envio.

Status e motivos

CampoSignificado
queuedAguardando para sair da nossa fila.
sentEnviado para a operadora, aguardando relatório de entrega. A maioria chega em minutos; algumas operadoras podem levar até 24 horas.
deliveredA operadora confirmou que o telefone recebeu.
failedNão entregue. O valor foi reembolsado ao seu saldo.
canceledNão enviado devido ao cancelamento. Reembolsado.
CampoSignificado
network_errorErro de rede
switched_offTelefone desligado ou fora de cobertura
not_in_serviceNúmero não está em serviço
blockedBloqueado pela operadora ou pelo destinatário
landlineLinha fixa ou número que não pode receber SMS
content_filterRejeitado pelo filtro de conteúdo da operadora
expiredExpirado: nenhum relatório antes do prazo da operadora
unknownResposta da operadora desconhecida
canceledCancelado antes do envio

Dúvidas sobre a API? Abra um ticket no console ou leia o FAQ.

Documentação da API de SMS em massa v1: Enviar, Cotar, Webhooks | SMSBulk