SDK oficial Node.js / TypeScript para a SMSGo — a API de SMS simples para o Brasil. Envie OTP/2FA, alertas transacionais e campanhas com poucas linhas de código.
- ⚡ Integra em minutos — autenticação cuidada pra você (sem ritual de token manual).
- 💸 Sem mensalidade — créditos pré-pagos que não expiram, preço em real.
- 🇧🇷 Brasil-first — entrega otimizada para Vivo, Claro, TIM, Oi e demais operadoras.
- 🟢 Zero dependências — usa o
fetchnativo (Node 18+). Tipado de ponta a ponta. - 🎁 R$ 10 grátis ao criar a conta — dá pra testar sem cartão.
Nova conta e chave em smsgo.com.br → painel → Minha conta → API.
npm install @orynlabs/smsgo
# ou: pnpm add @orynlabs/smsgo / yarn add @orynlabs/smsgoimport { SMSGo } from '@orynlabs/smsgo'
const smsgo = new SMSGo({ apiKey: process.env.SMSGO_KEY! })
const result = await smsgo.send({
phone: '+5511999990000',
message: 'Olá do SMSGo 👋',
})
console.log(result.id, result.status) // -> "a1b2c3...", "queued"Você passa só a apiKey. O SDK troca a chave por um token Bearer (válido 48h), guarda em cache e renova sozinho quando expira ou a API retornar 401.
const code = String(Math.floor(100000 + Math.random() * 900000)) // 6 dígitos
await smsgo.send({
phone: user.phone,
message: `Seu código SMSGo é ${code}. Válido por 5 minutos.`,
})
// guarde `code` (com TTL) e compare na verificaçãoawait smsgo.sendBulk({
messages: [
{ phone: '+5511999990000', message: 'Oi, Ana!' },
{ phone: '+5521988887777', message: 'Oi, Bruno!' },
],
urlCallback: 'https://seuapp.com/webhooks/smsgo', // status de entrega (opcional)
})const page = await smsgo.list({ page: 1 }) // { meta, data: SendListItem[] }
const one = await smsgo.get('a1b2c3-...') // detalhe + summary de entregas
// Números por bucket, paginado — útil para envios grandes:
const failed = await smsgo.getNumbers('a1b2c3-...', { status: 'failed', page: 1 })Use a chave de teste (prefixo test_, no painel → Minha conta → API) como apiKey. Nada muda no código: os envios não debitam saldo nem são despachados de verdade, as respostas são idênticas às de produção (com test: true) e os webhooks disparam com o mesmo flag.
const sandbox = new SMSGo({ apiKey: process.env.SMSGO_TEST_KEY! })
const r = await sandbox.send({ phone: '+5511999990000', message: 'Teste' })
console.log(r.test) // true
await sandbox.resolveMode() // "test" (ou `sandbox.mode` após a 1ª chamada)const { balance, currency } = await smsgo.getBalance() // { balance: 9.3, currency: 'BRL', company }
const types = await smsgo.getSmsTypes() // [{ id, name, price, sale }] — id vai em smsTypeIdCobra um cartão salvo sem abrir o painel (o cartão é cadastrado no painel via Stripe; a API só cobra um já salvo).
const plans = await smsgo.billing.plans() // pacotes por faixa
const cards = await smsgo.billing.cards() // 4 últimos dígitos
const receipt = await smsgo.billing.purchase({ quantity: 5000 /*, planId, cardId, coupon */ })
console.log(receipt.status) // 'succeeded' já creditou | 'processing' confirma via webhook
const invoices = await smsgo.billing.invoices({ page: 1 })Idempotência: cada
purchasegera uma cobrança nova. Em timeout, consultebilling.invoices()antes de repetir — não faça retry cego.
await smsgo.setAutoRecharge({
enabled: true,
threshold: 5, // recarrega quando o saldo ≤ R$ 5
planQuantity: 5000, // créditos por recarga
cardId: '<uuid>', // obrigatório p/ ligar
alertEnabled: true,
alertThreshold: 15, // e-mail quando o saldo ≤ R$ 15
})
const cfg = await smsgo.getAutoRecharge()// Define a URL que recebe `sms.status` (DLR) e `sms.reply` (resposta). Guarde o secret.
const { url, secret } = await smsgo.setWebhook({ url: 'https://seuapp.com/webhooks/smsgo' })
await smsgo.setWebhook({ rotateSecret: true }) // gira o segredo
await smsgo.setWebhook({ url: '' }) // desativaCada requisição traz X-SMSGo-Signature: sha256=<hmac> — o HMAC-SHA256 do corpo bruto com o seu secret. Valide sempre com o helper verifyWebhookSignature (comparação em tempo constante):
import { verifyWebhookSignature } from '@orynlabs/smsgo'
// `rawBody` deve ser o corpo BRUTO (Buffer/string), antes de qualquer parse.
const ok = verifyWebhookSignature(rawBody, req.headers['x-smsgo-signature'], secret)
if (!ok) return res.writeHead(401).end() // assinatura inválidaVeja o exemplo completo em examples/receive-dlr-webhook.mjs.
const listId = (await smsgo.lists.create({ name: 'Clientes VIP' })).id
const contactId = await smsgo.contacts.create({
fullName: 'Ana Souza',
phone: '+5511999990000',
email: 'ana@exemplo.com',
lists: [listId],
})
await smsgo.contacts.list({ page: 1, search: 'ana' }) // { meta, data }
await smsgo.contacts.update(contactId, { fullName: 'Ana S.', phone: '+5511999990000' })
await smsgo.contacts.delete(contactId)Toda resposta não-2xx vira um SMSGoError com status e um code estável:
import { SMSGo, SMSGoError } from '@orynlabs/smsgo'
try {
await smsgo.send({ phone: '+5511999990000', message: 'Olá' })
} catch (err) {
if (err instanceof SMSGoError) {
switch (err.code) {
case 'insufficient_balance': // 402 — sem saldo
case 'rate_limited': // 429 — muitas requisições (veja err.details)
case 'validation_error': // 422 — dados inválidos (veja err.errors)
default:
console.error(err.status, err.code, err.message)
}
}
}Em falhas de validação (422), err.errors traz o detalhe por campo ({ field, message }[]).
code |
HTTP | Significado |
|---|---|---|
bad_request |
400 | Requisição malformada |
unauthorized |
401 | Chave/token inválido |
insufficient_balance |
402 | Saldo insuficiente |
provider_out_of_stock |
409 | Estoque do provedor indisponível |
validation_error |
422 | Dados do request inválidos |
rate_limited |
429 | Limite de requisições atingido |
card_declined |
402 | Cartão recusado na compra |
authentication_required |
402 | Cartão exige autenticação (SCA) |
card_required |
400 | Nenhum cartão apto à cobrança |
payment_unavailable |
503 | Gateway de pagamento indisponível |
| Opção | Tipo | Default | Descrição |
|---|---|---|---|
apiKey |
string |
— | Obrigatório. Sua SMSGo-key. |
baseUrl |
string |
https://api.smsgo.com.br |
Só altere se a SMSGo orientar. |
fetch |
typeof fetch |
globalThis.fetch |
Injete um fetch (ex.: undici). |
SMS
send(params)→SendResult— envia um SMS. Campos:phone,message,schedule?(ISO-8601),reference?,from?,smsTypeId?.sendBulk(params)→SendResult— envia várias mensagens numa transação (até 5000).list({ page })→Paginated<SendListItem>— lista paginada de envios.get(id)→SendDetail— detalha um envio (comsummary).getNumbers(id, { status?, page? })→Paginated<SendNumberItem>— números do envio por bucket.getSmsTypes()→SmsTypeItem[]— catálogo de tipos de SMS.
Conta
getBalance()→Balance— saldo em R$ + dados da conta.getAutoRecharge()/setAutoRecharge(params)→AutoRechargeConfig— recarga automática + alerta.getWebhook()/setWebhook(params)→WebhookConfig— webhook de saída.mode/resolveMode()→'live' | 'test'— modo da chave atual.
Faturamento (smsgo.billing)
plans()→Plan[]·cards()→Card[]·invoices({ page?, perPage? })→Paginated<InvoiceItem>.purchase(params)→PurchaseResult— compra com cartão salvo (off-session).
Contatos (smsgo.contacts) e Listas (smsgo.lists)
list(params)·create(input)·get(id)·update(id, input)·delete(id).
Referência de máquina completa: smsgo.apidog.io — importável no Apidog/Postman.
Na pasta examples/ (Node 18+):
npm install
SMSGO_KEY=suachave node examples/send-sms.mjs
SMSGO_KEY=suachave node examples/send-otp.mjs +5511999990000
SMSGO_KEY=suachave node examples/check-status.mjs
SMSGO_KEY=suachave node examples/check-balance.mjs
SMSGO_KEY=suachave node examples/buy-credits.mjs
SMSGO_KEY=suachave node examples/configure-webhook.mjs
SMSGO_WEBHOOK_SECRET=whsec_... node examples/receive-dlr-webhook.mjsSMSGo foca em DX simples e preço em real. Sem cadastro de remetente pra começar, sem cobrança em dólar, créditos que não expiram. Documentação completa da API: smsgo.apidog.io.
MIT © SMSGo