Se você precisa automatizar verificações por SMS, integrar números virtuais no seu pipeline de testes ou construir um produto em cima de infraestrutura de SMS, a API do SMSCode foi projetada exatamente para isso. Neste guia, vamos do básico à integração completa — com exemplos reais de código em múltiplas linguagens, boas práticas de produção e tratamento de erros.
TL;DR: A API REST do SMSCode usa autenticação por Bearer Token, retorna JSON e segue um fluxo simples: obter número → aguardar SMS → ler código. Acesse a documentação completa ou crie sua conta para gerar seu token de API.
Pré-requisitos
Antes de começar, você vai precisar de:
- Uma conta ativa no SMSCode
- Saldo de crédito disponível (veja planos e preços)
- Seu token de API — disponível em Configurações → API na conta
O token tem 64 caracteres hexadecimais e se parece com: a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4...
Segurança do token: Trate o token exatamente como uma senha. Não comite em repositórios públicos, não exponha no frontend, não envie por e-mail ou chat. Se um token for comprometido, revogue-o imediatamente em Configurações → API e gere um novo.
Autenticação
Todas as requisições autenticadas usam o header HTTP Authorization:
Authorization: Bearer SEU_TOKEN_AQUI
Respostas de erro de autenticação:
401 Unauthorized— token ausente ou inválido403 Forbidden— token válido mas sem permissão para a operação
Formato de Resposta
A API retorna sempre JSON com estrutura consistente:
Sucesso:
{
"success": true,
"data": { ... }
}
Erro:
{
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Descrição humana do erro"
}
}
Visão Geral do Fluxo
O ciclo de vida de uma verificação via API tem quatro etapas:
1. GET /v1/catalog → Listar serviços disponíveis e preços
2. POST /v1/orders → Criar pedido (obtém número virtual)
3. GET /v1/orders/{id} → Consultar status e ler SMS recebido (polling)
4. DELETE /v1/orders/{id} → Cancelar pedido (se não precisar mais)
Vamos ver cada etapa em detalhe, com exemplos práticos.
1. Consultando o Catálogo
Antes de criar um pedido, consulte os serviços e países disponíveis:
# Listar todos os serviços disponíveis para Instagram no Brasil
curl -X GET "https://api.smscode.gg/v1/catalog?country=br&service=ig" \
-H "Authorization: Bearer SEU_TOKEN"
Resposta:
{
"success": true,
"data": [
{
"service": "ig",
"country": "br",
"price": 150,
"available": 42,
"currency": "credits"
}
]
}
Campos importantes:
price: Custo em créditos (unidade interna do SMSCode)available: Quantidade de números disponíveis agora para aquela combinaçãoservice: Código do serviço (veja lista completa na documentação)
Dica: Consulte o catálogo com cache de alguns minutos — ele muda gradualmente, não a cada segundo. Verificar disponibilidade antes de cada pedido é boa prática para evitar erro NO_NUMBERS_AVAILABLE.
2. Criando um Pedido (Obtendo Número Virtual)
curl -X POST "https://api.smscode.gg/v1/orders" \
-H "Authorization: Bearer SEU_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"service": "ig",
"country": "br"
}'
Resposta bem-sucedida:
{
"success": true,
"data": {
"id": "ord_abc123",
"phone": "+5511987654321",
"service": "ig",
"country": "br",
"status": "pending",
"expires_at": "2026-03-16T12:15:00Z",
"created_at": "2026-03-16T12:05:00Z"
}
}
Campos importantes:
id: Identificador único do pedido — guarde para consultas e cancelamentophone: O número virtual a ser inserido na plataforma alvostatus: Estado atual (pending,completed,expired,cancelled)expires_at: Quando o pedido expira se nenhum SMS for recebido
Próximo passo: Insira o valor de phone na plataforma (Instagram, WhatsApp, etc.) e solicite o envio do código SMS.
3. Consultando o Status e Lendo o SMS (Polling)
Após inserir o número na plataforma e solicitar o código, inicie o polling para aguardar o SMS:
curl -X GET "https://api.smscode.gg/v1/orders/ord_abc123" \
-H "Authorization: Bearer SEU_TOKEN"
Enquanto aguarda (status pending):
{
"success": true,
"data": {
"id": "ord_abc123",
"status": "pending",
"sms_code": null,
"sms_text": null
}
}
Após receber o SMS (status completed):
{
"success": true,
"data": {
"id": "ord_abc123",
"status": "completed",
"sms_code": "847291",
"sms_text": "Seu código do Instagram é 847291. Não compartilhe com ninguém.",
"received_at": "2026-03-16T12:06:32Z"
}
}
Campos importantes:
sms_code: O código numérico extraído automaticamente do texto (use este para inserir na plataforma)sms_text: Texto completo do SMS recebidoreceived_at: Timestamp de quando o SMS chegou
4. Cancelando um Pedido
Se decidir não usar mais o número ou precisar trocar:
curl -X DELETE "https://api.smscode.gg/v1/orders/ord_abc123" \
-H "Authorization: Bearer SEU_TOKEN"
Créditos são estornados parcialmente dependendo do tempo decorrido e do estado do pedido. Se o SMS já foi recebido, o cancelamento não gera reembolso.
Consultando Saldo
curl -X GET "https://api.smscode.gg/v1/balance" \
-H "Authorization: Bearer SEU_TOKEN"
{
"success": true,
"data": {
"balance": 4250,
"currency": "credits"
}
}
Útil para monitorar saldo programaticamente e emitir alertas quando estiver baixo.
Exemplos Completos em Linguagens Populares
Python (com tratamento de erros completo)
import requests
import time
import os
from typing import Optional
API_TOKEN = os.environ.get("SMSCODE_TOKEN")
BASE_URL = "https://api.smscode.gg/v1"
HEADERS = {
"Authorization": f"Bearer {API_TOKEN}",
"Content-Type": "application/json"
}
class SMSCodeClient:
def __init__(self, token: str):
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
self.base_url = BASE_URL
def get_number(self, service: str, country: str) -> dict:
"""Cria um pedido e retorna os dados do número virtual."""
response = requests.post(
f"{self.base_url}/orders",
headers=self.headers,
json={"service": service, "country": country}
)
response.raise_for_status()
data = response.json()
if not data["success"]:
raise ValueError(f"Erro ao criar pedido: {data['error']['message']}")
return data["data"]
def wait_for_sms(self, order_id: str, timeout: int = 300, interval: int = 5) -> Optional[str]:
"""Aguarda o SMS com polling. Retorna o código ou None em timeout."""
elapsed = 0
while elapsed < timeout:
time.sleep(interval)
elapsed += interval
response = requests.get(
f"{self.base_url}/orders/{order_id}",
headers=self.headers
)
data = response.json()["data"]
if data["status"] == "completed":
return data["sms_code"]
elif data["status"] in ["expired", "cancelled"]:
print(f"Pedido finalizado com status: {data['status']}")
return None
print("Timeout: SMS não chegou")
return None
def cancel_order(self, order_id: str) -> bool:
"""Cancela um pedido."""
response = requests.delete(
f"{self.base_url}/orders/{order_id}",
headers=self.headers
)
return response.json().get("success", False)
def get_balance(self) -> int:
"""Retorna o saldo atual em créditos."""
response = requests.get(f"{self.base_url}/balance", headers=self.headers)
return response.json()["data"]["balance"]
# Uso prático
def get_verification_code(service: str, country: str) -> Optional[tuple]:
"""Retorna (phone, code) ou None em caso de falha."""
client = SMSCodeClient(API_TOKEN)
# Verificar saldo antes
balance = client.get_balance()
print(f"Saldo atual: {balance} créditos")
try:
order = client.get_number(service, country)
phone = order["phone"]
order_id = order["id"]
print(f"Número obtido: {phone}")
code = client.wait_for_sms(order_id)
if code:
print(f"Código recebido: {code}")
return (phone, code)
else:
# Cancelar se não recebeu
client.cancel_order(order_id)
return None
except requests.exceptions.RequestException as e:
print(f"Erro de rede: {e}")
return None
except ValueError as e:
print(f"Erro da API: {e}")
return None
# Exemplo de uso
result = get_verification_code("ig", "br")
if result:
phone, code = result
print(f"Use o número {phone} com o código {code}")
Node.js / TypeScript
import fetch from 'node-fetch';
const API_TOKEN = process.env.SMSCODE_TOKEN!;
const BASE_URL = 'https://api.smscode.gg/v1';
interface OrderData {
id: string;
phone: string;
service: string;
country: string;
status: 'pending' | 'completed' | 'expired' | 'cancelled';
sms_code?: string;
sms_text?: string;
expires_at: string;
}
const headers = {
'Authorization': `Bearer ${API_TOKEN}`,
'Content-Type': 'application/json',
};
async function createOrder(service: string, country: string): Promise<OrderData> {
const res = await fetch(`${BASE_URL}/orders`, {
method: 'POST',
headers,
body: JSON.stringify({ service, country }),
});
const body = await res.json() as any;
if (!body.success) throw new Error(body.error.message);
return body.data;
}
async function pollForSms(
orderId: string,
timeoutMs = 300_000,
intervalMs = 5_000
): Promise<string | null> {
const deadline = Date.now() + timeoutMs;
while (Date.now() < deadline) {
await new Promise(r => setTimeout(r, intervalMs));
const res = await fetch(`${BASE_URL}/orders/${orderId}`, { headers });
const body = await res.json() as any;
const data: OrderData = body.data;
if (data.status === 'completed' && data.sms_code) {
return data.sms_code;
}
if (['expired', 'cancelled'].includes(data.status)) {
console.log(`Pedido finalizado: ${data.status}`);
return null;
}
}
console.log('Timeout');
return null;
}
async function cancelOrder(orderId: string): Promise<void> {
await fetch(`${BASE_URL}/orders/${orderId}`, { method: 'DELETE', headers });
}
// Uso
async function getVerificationCode(service: string, country: string) {
const order = await createOrder(service, country);
console.log(`Número: ${order.phone}`);
const code = await pollForSms(order.id);
if (code) {
console.log(`Código: ${code}`);
return { phone: order.phone, code };
} else {
await cancelOrder(order.id);
return null;
}
}
getVerificationCode('wa', 'us').then(console.log).catch(console.error);
PHP
<?php
class SMSCodeClient {
private string $token;
private string $baseUrl = 'https://api.smscode.gg/v1';
public function __construct(string $token) {
$this->token = $token;
}
private function request(string $method, string $endpoint, array $data = null): array {
$ch = curl_init($this->baseUrl . $endpoint);
curl_setopt_array($ch, [
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CUSTOMREQUEST => $method,
CURLOPT_HTTPHEADER => [
"Authorization: Bearer {$this->token}",
"Content-Type: application/json",
],
]);
if ($data !== null) {
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
}
$response = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($response === false) {
throw new \RuntimeException('Erro de rede na requisição');
}
$decoded = json_decode($response, true);
if (!$decoded['success']) {
throw new \RuntimeException($decoded['error']['message']);
}
return $decoded['data'];
}
public function createOrder(string $service, string $country): array {
return $this->request('POST', '/orders', [
'service' => $service,
'country' => $country,
]);
}
public function getOrder(string $orderId): array {
return $this->request('GET', "/orders/{$orderId}");
}
public function cancelOrder(string $orderId): array {
return $this->request('DELETE', "/orders/{$orderId}");
}
public function waitForSms(string $orderId, int $timeoutSeconds = 300): ?string {
$deadline = time() + $timeoutSeconds;
while (time() < $deadline) {
sleep(5);
$data = $this->getOrder($orderId);
if ($data['status'] === 'completed') {
return $data['sms_code'];
}
if (in_array($data['status'], ['expired', 'cancelled'])) {
return null;
}
}
return null;
}
}
// Uso
$client = new SMSCodeClient(getenv('SMSCODE_TOKEN'));
try {
$order = $client->createOrder('tg', 'ru');
echo "Número: {$order['phone']}\n";
$code = $client->waitForSms($order['id']);
if ($code) {
echo "Código: {$code}\n";
} else {
$client->cancelOrder($order['id']);
echo "SMS não chegou\n";
}
} catch (\RuntimeException $e) {
echo "Erro: " . $e->getMessage() . "\n";
}
?>
Tratamento de Erros
A API retorna erros no formato padrão com código e mensagem:
| Código HTTP | Código de erro | Descrição | Ação recomendada |
|---|---|---|---|
| 401 | UNAUTHORIZED | Token inválido ou ausente | Verifique o token |
| 402 | INSUFFICIENT_BALANCE | Saldo insuficiente | Adicione créditos |
| 404 | NO_NUMBERS_AVAILABLE | Nenhum número disponível | Tente outro país |
| 404 | ORDER_NOT_FOUND | ID de pedido inexistente | Verifique o ID |
| 429 | RATE_LIMIT_EXCEEDED | Muitas requisições | Aguarde Retry-After |
| 503 | SERVICE_UNAVAILABLE | Serviço temporariamente indisponível | Retry com backoff |
Implementando Retry com Backoff Exponencial
import time
import requests
def api_request_with_retry(url, headers, method="GET", data=None, max_retries=3):
delay = 1
for attempt in range(max_retries):
try:
if method == "GET":
response = requests.get(url, headers=headers, timeout=10)
elif method == "POST":
response = requests.post(url, headers=headers, json=data, timeout=10)
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", delay))
print(f"Rate limit. Aguardando {retry_after}s...")
time.sleep(retry_after)
continue
if response.status_code == 503:
print(f"Serviço indisponível. Tentativa {attempt + 1}/{max_retries}")
time.sleep(delay)
delay = min(delay * 2, 60) # backoff exponencial até 60s
continue
return response
except requests.exceptions.ConnectionError:
print(f"Erro de conexão. Tentativa {attempt + 1}/{max_retries}")
time.sleep(delay)
delay = min(delay * 2, 30)
raise Exception(f"Falha após {max_retries} tentativas")
Boas Práticas de Integração
Variáveis de ambiente para o token
# .env
SMSCODE_TOKEN=seu_token_aqui
# .gitignore — SEMPRE inclua:
.env
*.env
Polling eficiente
Recomendamos intervalo de 3–5 segundos entre consultas. Intervalos menores podem acionar rate limiting.
# Polling com backoff adaptativo
def smart_poll(order_id, max_attempts=60):
delay = 3
for attempt in range(max_attempts):
time.sleep(delay)
result = get_order_status(order_id)
if result["status"] == "completed":
return result["sms_code"]
if result["status"] in ["expired", "cancelled"]:
return None
# Aumenta delay gradualmente após 30s
if attempt > 6:
delay = min(delay * 1.2, 15)
return None
Sempre cancele pedidos não utilizados
# No finally block para garantir cancelamento
try:
order = create_order("ig", "br")
# ... lógica principal
code = wait_for_sms(order["id"])
return code
except Exception as e:
# Cancela se houver erro antes de receber o SMS
if order and order["id"]:
cancel_order(order["id"])
raise
Log estruturado para depuração
import logging
import json
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("smscode")
def logged_get_number(service: str, country: str):
logger.info(json.dumps({
"action": "create_order",
"service": service,
"country": country
}))
try:
order = create_order(service, country)
logger.info(json.dumps({
"action": "order_created",
"order_id": order["id"],
"phone": order["phone"]
}))
return order
except Exception as e:
logger.error(json.dumps({
"action": "create_order_failed",
"error": str(e)
}))
raise
Casos de Uso Comuns para Desenvolvedores
Testes automatizados de cadastro (E2E): Integre o SMSCode na suite de testes E2E (Playwright, Cypress, Selenium) para testar fluxos completos de registro com OTP real — sem mocks que não refletem o comportamento em produção.
# Exemplo com Playwright + SMSCode
from playwright.async_api import async_playwright
import asyncio
async def test_signup_flow():
client = SMSCodeClient(API_TOKEN)
order = client.get_number("ig", "br")
async with async_playwright() as p:
browser = await p.chromium.launch()
page = await browser.new_page()
await page.goto("https://www.instagram.com/accounts/signup/")
await page.fill("[name='phone_number']", order["phone"])
await page.click("[type='submit']")
# Aguardar SMS
code = client.wait_for_sms(order["id"])
await page.fill("[name='verification_code']", code)
await page.click("[type='submit']")
# Verificar sucesso
await page.wait_for_selector(".success-indicator")
print("Teste passou!")
await browser.close()
asyncio.run(test_signup_flow())
Monitoramento de disponibilidade: Verifique periodicamente se um serviço ainda está aceitando números de determinado país — útil para sistemas que dependem de verificações regulares.
Pipeline de onboarding em massa: Para plataformas que criam contas em serviços de terceiros em nome de usuários (como automação de agências), integre a API do SMSCode no fluxo de onboarding.
FAQ
A API do SMSCode é compatível com SMS-Activate?
Não diretamente. A API do SMSCode usa padrão REST com JSON, diferente do protocolo legado do SMS-Activate (que usa parâmetros de query string e respostas em texto plano). Se você está migrando de outro serviço, será necessário adaptar a integração — mas o modelo conceitual é o mesmo (criar pedido → polling → ler código).
Qual o intervalo recomendado para polling?
Entre 3 e 5 segundos. Intervalos menores que 2 segundos podem acionar rate limiting (HTTP 429). Use backoff suave após vários polls sem resposta. Em geral, SMS chegam entre 10 e 60 segundos após a solicitação na plataforma.
É possível receber webhook quando o SMS chegar?
Webhooks estão no roadmap do SMSCode. Por enquanto, polling é o método suportado. Para minimizar latência, inicie o polling imediatamente após criar o pedido e inserir o número na plataforma alvo.
O token de API tem o mesmo acesso que a conta web?
Sim. O token dá acesso completo à conta, incluindo criação de pedidos e leitura do histórico. Trate como senha: faça rotação periódica, não compartilhe, revogue imediatamente se suspeitar de comprometimento. Acesse Configurações → API para gerenciar tokens.
Como lidar com o caso onde o SMS nunca chega?
Implemente timeout máximo (5 minutos é razoável). Se o status ainda for pending após o timeout, cancele o pedido via DELETE e tente novamente com um novo número. Se falhar consistentemente para um país/serviço específico, tente outro país — pode haver indisponibilidade temporária naquela combinação.
Posso usar a API para verificar qualquer serviço disponível no catálogo?
Sim. Qualquer serviço listado no catálogo pode ser verificado via API. Para ver todos os serviços e códigos disponíveis, consulte GET /v1/catalog sem filtros (retorna o catálogo completo) ou acesse a documentação de serviços.