Guia Completo da API SMSCode para Desenvolvedores

Guia Completo da API SMSCode para Desenvolvedores

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:

  1. Uma conta ativa no SMSCode
  2. Saldo de crédito disponível (veja planos e preços)
  3. 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álido
  • 403 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.

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ção
  • service: 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 cancelamento
  • phone: O número virtual a ser inserido na plataforma alvo
  • status: 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 recebido
  • received_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 HTTPCódigo de erroDescriçãoAção recomendada
401UNAUTHORIZEDToken inválido ou ausenteVerifique o token
402INSUFFICIENT_BALANCESaldo insuficienteAdicione créditos
404NO_NUMBERS_AVAILABLENenhum número disponívelTente outro país
404ORDER_NOT_FOUNDID de pedido inexistenteVerifique o ID
429RATE_LIMIT_EXCEEDEDMuitas requisiçõesAguarde Retry-After
503SERVICE_UNAVAILABLEServiço temporariamente indisponívelRetry 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.

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.

Pronto para experimentar o SMSCode?

Crie uma conta e obtenha seu primeiro número virtual em menos de dois minutos.

Começar →