SDK oficial Python para a SMSGo — a API de SMS simples para o Brasil. Envie OTP/2FA, alertas transacionais e campanhas com poucas linhas.
- ⚡ 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 só a biblioteca padrão. Tipado (
py.typed). - 🎁 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.
pip install smsgoRequer Python 3.8+.
import os
from smsgo import SMSGo
smsgo = SMSGo(api_key=os.environ["SMSGO_KEY"])
result = smsgo.send(
phone="+5511999990000",
message="Olá do SMSGo 👋",
)
print(result.id, result.status) # -> "a1b2c3...", "queued"Você passa só a api_key. 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.
import secrets
smsgo = SMSGo(api_key=os.environ["SMSGO_KEY"])
# Gere o código no seu backend e armazene com TTL (ex.: Redis)
code = f"{secrets.randbelow(900000) + 100000:06d}"
smsgo.send(
phone=user.phone,
message=f"Seu código SMSGo é {code}. Válido por 5 minutos.",
)
# guarde `code` e compare na verificaçãosmsgo.send_bulk(
messages=[
{"phone": "+5511999990000", "message": "Oi, Ana!"},
{"phone": "+5521988887777", "message": "Oi, Bruno!"},
],
url_callback="https://seuapp.com/webhooks/smsgo", # status de entrega (opcional)
)page = smsgo.list(page=1) # Paginated(meta, data=[SendListItem, ...])
detail = smsgo.get("a1b2c3-...") # SendDetail com summary de entregas
print(detail.summary.delivered, detail.summary.done)
# Números de um envio, filtrando por bucket de status:
nums = smsgo.get_numbers("a1b2c3-...", status="failed", page=1) # delivered|failed|in_progressUse a chave de teste (prefixo test_, no painel → Minha conta → API) como api_key. 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.
sandbox = SMSGo(api_key=os.environ["SMSGO_TEST_KEY"])
print(sandbox.resolve_mode()) # 'test' (ou use a propriedade `sandbox.mode`)
r = sandbox.send(phone="+5511999990000", message="teste")
print(r.test) # Truemode retorna None antes da 1ª chamada autenticada; resolve_mode() força a resolução.
balance = smsgo.get_balance()
print(balance.balance, balance.currency) # 42.50 'BRL'
print(balance.company["name"])
for t in smsgo.get_sms_types(): # catálogo (id vai em sms_type_id)
print(t.id, t.name, t.sale or t.price)billing.purchase cobra um cartão salvo off-session. Informe quantity ou plan_id; sem card_id, usa o cartão padrão.
⚠️ Não é idempotente: cada chamada gera uma cobrança nova. Em timeout, consultesmsgo.billing.invoices()antes de repetir — não faça retry cego.
plans = smsgo.billing.plans() # pacotes (tiers)
cards = smsgo.billing.cards() # cartões salvos (4 últimos dígitos)
receipt = smsgo.billing.purchase(quantity=1000, card_id=cards[0].id)
print(receipt.status) # 'succeeded' já creditou o saldo | 'processing' confirma via webhook
print(receipt.invoice_uuid, receipt.total)
# Recarga automática + alerta de saldo:
smsgo.set_auto_recharge(
enabled=True,
threshold=10, # recarrega quando o saldo <= R$ 10
plan_quantity=1000, # compra 1000 créditos a cada recarga
card_id=cards[0].id, # obrigatório p/ ligar
alert_enabled=True,
alert_threshold=15, # e-mail quando o saldo <= R$ 15
)
cfg = smsgo.get_auto_recharge()# Define a URL que recebe `sms.status` (DLR) e `sms.reply` (resposta). Guarde o secret.
cfg = smsgo.set_webhook(url="https://seuapp.com/webhooks/smsgo")
print(cfg.url, cfg.secret)
smsgo.set_webhook(rotate_secret=True) # gira o segredo
smsgo.set_webhook(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 embutido (comparação em tempo constante, nunca levanta exceção):
from smsgo import verify_webhook_signature
# raw_body: bytes/str exatamente como recebido (NÃO reparseie antes de validar)
ok = verify_webhook_signature(raw_body, request.headers["X-SMSGo-Signature"], secret)
if not ok:
return "invalid signature", 401Servidor completo em examples/receive_dlr_webhook.py.
list_id = smsgo.lists.create(name="Clientes VIP").id
contact_id = smsgo.contacts.create(
full_name="Ana Souza",
phone="+5511999990000",
email="ana@exemplo.com",
lists=[list_id],
)
smsgo.contacts.list(page=1, search="ana") # Paginated(meta, data)
smsgo.contacts.update(contact_id, full_name="Ana S.", phone="+5511999990000")
smsgo.contacts.delete(contact_id)Toda resposta não-2xx vira um SMSGoError com status e um code estável:
from smsgo import SMSGo, SMSGoError
smsgo = SMSGo(api_key=os.environ["SMSGO_KEY"])
try:
smsgo.send(phone="+5511999990000", message="Olá")
except SMSGoError as err:
if err.code == "insufficient_balance": # 402 — sem saldo
...
elif err.code == "rate_limited": # 429 — muitas requisições
...
elif err.code == "validation_error": # 422 — detalhe por campo
for fe in err.errors or []:
print(fe.field, fe.message)
else:
print(err.status, err.code, err.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 |
card_required |
400 | Nenhum cartão apto à cobrança |
payment_unavailable |
503 | Pagamento temporariamente fora |
network_error |
0 | Falha de rede/transporte |
| Parâmetro | Tipo | Default | Descrição |
|---|---|---|---|
api_key |
str |
— | Obrigatório. Sua SMSGo-key. |
base_url |
str |
https://api.smsgo.com.br |
Só altere se a SMSGo orientar. |
timeout |
float |
30.0 |
Timeout das requisições (s). |
send(phone, message, *, schedule=None, reference=None, sender=None, sms_type_id=None)→SendResultsend_bulk(messages, *, url_callback=None, flash_sms=None, sms_type_id=None)→SendResultlist(page=1)→Paginated[SendListItem]get(id)→SendDetailget_numbers(id, *, status=None, page=None)→Paginated[SendNumberItem]get_sms_types()→list[SmsTypeItem]get_balance()→Balanceget_auto_recharge()/set_auto_recharge(...)→AutoRechargeConfigget_webhook()/set_webhook(...)→WebhookConfigresolve_mode()→'live' | 'test'· propriedademode→'live' | 'test' | None
senderé mapeado para o campofromda API (palavra reservada em Python).
list(*, page, per_page=None, search=None, title=None)→Paginatedcreate(*, full_name, phone, email=None, lists=None)→str(UUID)get(id)→ContactDetail·update(id, ...)→str·delete(id)→dict
list(*, page, per_page=None, title=None)→Paginatedcreate(*, name)/get(id)/update(id, *, name)→ListResult·delete(id)→dict
plans()→list[Plan]·cards()→list[Card]invoices(*, page=None, per_page=None)→Paginated[InvoiceItem]purchase(*, quantity=None, plan_id=None, card_id=None, coupon=None)→PurchaseResult(não idempotente)
verify_webhook_signature(raw_body, signature_header, secret)→bool— validaX-SMSGo-Signatureem tempo constante.
Na pasta examples/:
SMSGO_KEY=suachave python examples/send_sms.py +5511999990000
SMSGO_KEY=suachave python examples/send_otp.py +5511999990000
SMSGO_KEY=suachave python examples/check_status.py
SMSGO_KEY=suachave python examples/check_balance.py
SMSGO_KEY=suachave python examples/buy_credits.py
SMSGO_KEY=suachave python examples/configure_webhook.py https://seuapp.com/webhooks/smsgo
SMSGO_WEBHOOK_SECRET=whsec_... python examples/receive_dlr_webhook.pySMSGo 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. Há também os SDKs oficiais Node.js, Go e PHP.
MIT © SMSGo