Documentación de la API

v1.0.0

Acceso programático a números virtuales, pedidos y saldo de cuenta.

Autenticación

Todas las solicitudes a la API requieren un Bearer token. Genera uno desde Configuración de la Cuenta en el panel, y luego inclúyelo en cada solicitud:

Authorization: Bearer YOUR_API_TOKEN

Las solicitudes sin un token válido reciben una respuesta 401 UNAUTHORIZED.

URL Base

Todas las rutas de endpoints a continuación son relativas a:

https://api.smscode.gg/v1

Formato de Respuesta

Cada respuesta devuelve JSON con una estructura consistente. Todas las respuestas incluyen un encabezado x-request-id para depuración.

Éxito
{
  "success": true,
  "data": { ... }
}
Error
{
  "success": false,
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable message"
  }
}
GET /catalog/countries

Devuelve una lista de todos los países disponibles.

Parámetros

Ninguno

Ejemplo de Solicitud

curl -s https://api.smscode.gg/v1/catalog/countries \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/catalog/countries", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/catalog/countries",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": [
    {
      "id": 6,
      "code": "ID",
      "name": "Indonesia",
      "dial_code": "+62",
      "emoji": "🇮🇩",
      "active": true
    }
  ]
}
GET /catalog/services

Devuelve una lista de servicios (plataformas) disponibles. Opcionalmente filtra por país.

Parámetros de Consulta

NombreTipoRequeridoDescripción
country_idintegerNoFiltrar servicios disponibles para este país

Ejemplo de Solicitud

curl -s "https://api.smscode.gg/v1/catalog/services?country_id=6" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/catalog/services?country_id=6", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/catalog/services",
    params={"country_id": 6},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": [
    {
      "id": 3,
      "code": "wa",
      "name": "WhatsApp",
      "active": true
    }
  ]
}
GET /catalog/products

Devuelve una lista paginada de productos disponibles. Filtra por país y/o plataforma.

Parámetros de Consulta

NombreTipoRequeridoDescripción
country_idintegerNoFiltrar por ID de país
platform_idintegerNoFiltrar por ID de plataforma/servicio
sortstringNoOrden de clasificación: price_asc (predeterminado), price_desc, available_asc, available_desc, name_asc, name_desc
limitintegerNoResultados por página (1-10.000, predeterminado 1.000)
pageintegerNoNúmero de página (mínimo 1, predeterminado 1)

Ejemplo de Solicitud

curl -s "https://api.smscode.gg/v1/catalog/products?country_id=6&platform_id=3&limit=10&page=1" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const params = new URLSearchParams({
  country_id: "6", platform_id: "3", limit: "10", page: "1",
});
const res = await fetch(`https://api.smscode.gg/v1/catalog/products?${params}`, {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/catalog/products",
    params={"country_id": 6, "platform_id": 3, "limit": 10, "page": 1},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": [
    {
      "id": 142,
      "name": "WhatsApp Indonesia",
      "country_id": 6,
      "platform_id": 3,
      "available": 42,
      "price": 15000,
      "active": true
    }
  ],
  "meta": { "page": 1, "limit": 10, "count": 1 }
}
GET /catalog/exchange-rate

Devuelve la tasa de cambio actual para un par de divisas. Útil para convertir precios.

Parámetros de Consulta

NombreTipoRequeridoDescripción
pairstringNoPar de divisas (predeterminado: USD/IDR)

Ejemplo de Solicitud

curl -s "https://api.smscode.gg/v1/catalog/exchange-rate?pair=USD/IDR" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/catalog/exchange-rate?pair=USD/IDR", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/catalog/exchange-rate",
    params={"pair": "USD/IDR"},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "pair": "USD/IDR",
    "base_currency": "USD",
    "quote_currency": "IDR",
    "rate": 16250
  }
}
GET /balance

Devuelve el saldo de cuenta del usuario autenticado en IDR.

Parámetros

Ninguno

Ejemplo de Solicitud

curl -s https://api.smscode.gg/v1/balance \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/balance", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/balance",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "currency": "IDR",
    "balance": 500000
  }
}
GET /orders

Devuelve una lista de los pedidos del usuario autenticado, ordenados por más recientes. Admite filtrado por estado y paginación mediante offset.

Parámetros de Consulta

NombreTipoRequeridoDescripción
limitintegerNoMáximo de resultados (1-100, predeterminado 20)
offsetintegerNoNúmero de resultados a omitir (predeterminado 0)
statusstringNoFiltrar por estado: ACTIVE, OTP_RECEIVED, COMPLETED, CANCELED, EXPIRED (sin distinción de mayúsculas)

Ejemplo de Solicitud

curl -s "https://api.smscode.gg/v1/orders?limit=5&status=ACTIVE" \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const params = new URLSearchParams({
  limit: "5", status: "ACTIVE", offset: "0",
});
const res = await fetch(`https://api.smscode.gg/v1/orders?${params}`, {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/orders",
    params={"limit": 5, "status": "ACTIVE", "offset": 0},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": [
    {
      "id": 1001,
      "status": "ACTIVE",
      "created_at": "2026-02-25T10:00:00Z",
      "product_id": 142,
      "phone_number": "+6281234567890",
      "amount": 15000,
      "otp_code": null,
      "otp_received_at": null,
      "expires_at": "2026-02-25T10:20:00Z",
      "canceled_at": null,
      "failed_reason": null
    }
  ]
}
GET /orders/{id}

Devuelve un pedido individual por ID. Solo devuelve pedidos del usuario autenticado.

Parámetros de Ruta

NombreTipoRequeridoDescripción
idintegerID del pedido (parámetro de ruta)

Ejemplo de Solicitud

curl -s https://api.smscode.gg/v1/orders/1001 \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/orders/1001", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/orders/1001",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "id": 1001,
    "status": "OTP_RECEIVED",
    "created_at": "2026-02-25T10:00:00Z",
    "product_id": 142,
    "phone_number": "+6281234567890",
    "amount": 15000,
    "otp_code": "123456",
    "otp_received_at": "2026-02-25T10:05:00Z",
    "expires_at": "2026-02-25T10:20:00Z",
    "canceled_at": null,
    "failed_reason": null
  }
}
GET /orders/active

Lista todos los pedidos actualmente activos (ACTIVE + OTP_RECEIVED). Úsalo para consultar actualizaciones de estado de OTP.

Parámetros

Ninguno

Ejemplo de Solicitud

curl -s https://api.smscode.gg/v1/orders/active \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/orders/active", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/orders/active",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": [
    {
      "id": 1001,
      "status": "OTP_RECEIVED",
      "otp_code": "123456",
      "otp_message": "Your verification code is 123456",
      "otp_received_at": "2026-02-25T10:05:00Z",
      "expires_at": "2026-02-25T10:20:00Z",
      "failed_reason": null
    },
    {
      "id": 1002,
      "status": "ACTIVE",
      "otp_code": null,
      "otp_message": null,
      "otp_received_at": null,
      "expires_at": "2026-02-25T10:50:00Z",
      "failed_reason": null
    }
  ]
}
POST /orders/create

Crea un nuevo pedido de número virtual. Deduce el saldo automáticamente. Admite un encabezado opcional Idempotency-Key para evitar pedidos duplicados en reintentos de red.

Cuerpo de la Solicitud

NombreTipoRequeridoDescripción
product_idintegerID del producto a pedir
quantityintegerNoCantidad de artículos (1-100, predeterminado 1)

Pasa un encabezado Idempotency-Key (cualquier cadena única) para reintentar solicitudes de forma segura sin crear pedidos duplicados.

Ejemplo de Solicitud

curl -s -X POST https://api.smscode.gg/v1/orders/create \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: unique-request-id-123" \
  -d '{"product_id":142,"quantity":1}'
const res = await fetch("https://api.smscode.gg/v1/orders/create", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
    "Idempotency-Key": "unique-request-id-123",
  },
  body: JSON.stringify({ product_id: 142, quantity: 1 }),
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/orders/create",
    json={"product_id": 142, "quantity": 1},
    headers={
        "Authorization": "Bearer YOUR_API_TOKEN",
        "Idempotency-Key": "unique-request-id-123",
    })
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "orders": [
      {
        "id": 1002,
        "status": "ACTIVE",
        "phone_number": "+6281234567891",
        "otp_code": null,
        "otp_received_at": null,
        "expires_at": "2026-02-25T10:50:00Z",
        "failed_reason": null
      }
    ],
    "failed_count": 0
  }
}
POST /orders/cancel

Cancela un pedido activo. El costo del alquiler se reembolsa al saldo de tu cuenta.

Cuerpo de la Solicitud

NombreTipoRequeridoDescripción
idintegerID del pedido a cancelar

Ejemplo de Solicitud

curl -s -X POST https://api.smscode.gg/v1/orders/cancel \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id":1001}'
const res = await fetch("https://api.smscode.gg/v1/orders/cancel", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/orders/cancel",
    json={"id": 1001},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "order_id": 1001,
    "status": "CANCELED",
    "refund_amount": 15000,
    "new_balance": 515000
  }
}
POST /orders/finish

Marca un pedido como completado después de recibir el OTP. Esto libera el número inmediatamente en lugar de esperar a que expire.

Cuerpo de la Solicitud

NombreTipoRequeridoDescripción
idintegerID del pedido a finalizar

Ejemplo de Solicitud

curl -s -X POST https://api.smscode.gg/v1/orders/finish \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id":1001}'
const res = await fetch("https://api.smscode.gg/v1/orders/finish", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/orders/finish",
    json={"id": 1001},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "order_id": 1001,
    "status": "COMPLETED"
  }
}
POST /orders/resend

Solicita que la plataforma reenvíe el SMS al número alquilado. No todas las plataformas soportan el reenvío — verifica el campo resent en la respuesta.

Cuerpo de la Solicitud

NombreTipoRequeridoDescripción
idintegerID del pedido para reenviar SMS

Ejemplo de Solicitud

curl -s -X POST https://api.smscode.gg/v1/orders/resend \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"id":1001}'
const res = await fetch("https://api.smscode.gg/v1/orders/resend", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ id: 1001 }),
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/orders/resend",
    json={"id": 1001},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "order_id": 1001,
    "status": "ACTIVE",
    "resent": true
  }
}
GET /webhook

Devuelve tu configuración actual de notificaciones webhook.

Parámetros

Ninguno

Ejemplo de Solicitud

curl -s https://api.smscode.gg/v1/webhook \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/webhook", {
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.get("https://api.smscode.gg/v1/webhook",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "webhook_url": "https://example.com/webhook",
    "webhook_secret": "a1b2c3d4e5f6..."
  }
}
PATCH /webhook

Actualiza tu URL de webhook y/o secreto. Se genera un secreto automáticamente cuando estableces una URL por primera vez. Envía una cadena vacía para borrar. La URL debe usar HTTPS.

Cuerpo de la Solicitud

NombreTipoRequeridoDescripción
webhook_urlstringNoURL HTTPS para recibir eventos webhook (cadena vacía para borrar)
webhook_secretstringNoSecreto compartido para firma HMAC-SHA256 (se genera automáticamente si se omite en la primera configuración)

Se requiere al menos un campo.

Ejemplo de Solicitud

curl -s -X PATCH https://api.smscode.gg/v1/webhook \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"webhook_url":"https://example.com/webhook"}'
const res = await fetch("https://api.smscode.gg/v1/webhook", {
  method: "PATCH",
  headers: {
    Authorization: "Bearer YOUR_API_TOKEN",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ webhook_url: "https://example.com/webhook" }),
});
const data = await res.json();
import requests

res = requests.patch("https://api.smscode.gg/v1/webhook",
    json={"webhook_url": "https://example.com/webhook"},
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "webhook_url": "https://example.com/webhook",
    "webhook_secret": "a1b2c3d4e5f6..."
  }
}
POST /webhook/test

Envía un evento de prueba a tu URL de webhook configurada. Devuelve el código de estado HTTP de tu servidor. Útil para verificar que tu endpoint funciona antes de ponerlo en producción.

Parámetros

Ninguno

Ejemplo de Solicitud

curl -s -X POST https://api.smscode.gg/v1/webhook/test \
  -H "Authorization: Bearer YOUR_API_TOKEN"
const res = await fetch("https://api.smscode.gg/v1/webhook/test", {
  method: "POST",
  headers: { Authorization: "Bearer YOUR_API_TOKEN" },
});
const data = await res.json();
import requests

res = requests.post("https://api.smscode.gg/v1/webhook/test",
    headers={"Authorization": "Bearer YOUR_API_TOKEN"})
data = res.json()

Ejemplo de Respuesta

200 OK
{
  "success": true,
  "data": {
    "status_code": 200
  }
}

Notificaciones Webhook

Configura una URL de webhook para recibir notificaciones push en tiempo real de eventos de pedidos en lugar de hacer polling. Este es el enfoque recomendado para scripts de bots.

Eventos

EventoDisparador
order.otp_receivedCódigo OTP entregado al número alquilado
order.completedPedido marcado como completado (manual o por expiración)
order.expiredPedido expirado sin OTP (saldo reembolsado)
order.canceledPedido cancelado por el usuario (saldo reembolsado)

Payload

Cuerpo del POST Webhook
{
  "event": "order.otp_received",
  "timestamp": "2026-02-25T12:00:00Z",
  "data": {
    "order_id": 1001,
    "phone_number": "+628123456789",
    "otp_code": "1234",
    "otp_message": "Your verification code is 1234",
    "product_id": 42,
    "country": "Indonesia",
    "platform": "WhatsApp"
  }
}

Verificación de Firma

Cada solicitud webhook incluye un encabezado X-Webhook-Signature con una firma HMAC-SHA256 del cuerpo de la solicitud, usando tu webhook_secret como clave:

X-Webhook-Signature: sha256={HMAC-SHA256(body, webhook_secret)}

Verifica esta firma en tu servidor para asegurar que la solicitud es auténtica. La entrega es de tipo disparar y olvidar con un tiempo de espera de 3 segundos y sin reintentos.

Rate Limits

Las solicitudes a la API tienen rate limits por grupo de endpoints. Exceder el límite devuelve 429 Too Many Requests con un encabezado Retry-After indicando cuántos segundos esperar.

Grupo de EndpointsLímiteVentana
Catálogo (países, servicios, productos, tasa de cambio)1.200 solicitudes60 segundos
Saldo600 solicitudes60 segundos
Lectura de pedidos (listar, obtener, activos)1.200 solicitudes60 segundos
Crear pedido1.200 solicitudes60 segundos
Cancelar pedido600 solicitudes60 segundos
Acciones de pedido (finalizar, reenviar)600 solicitudes60 segundos
Configuración de webhook (obtener, actualizar, probar)120 solicitudes60 segundos

Códigos de Error

Las respuestas de error incluyen uno de estos códigos en error.code:

CódigoHTTPDescripción
UNAUTHORIZED401Token de la API faltante o inválido
FORBIDDEN403Acceso denegado
NOT_FOUND404Recurso no encontrado (pedido, tasa de cambio, etc.)
CONFLICT409Solicitud duplicada o conflicto de recursos
INSUFFICIENT_BALANCE409Saldo insuficiente para crear el pedido
VALIDATION_ERROR422Los parámetros de la solicitud no pasaron la validación
RATE_LIMIT_EXCEEDED429Demasiadas solicitudes (verifica el encabezado Retry-After)
INTERNAL_ERROR500Error interno del servidor
PROVIDER_ERROR422El proveedor SMS ascendente rechazó la solicitud
CANCEL_TOO_EARLY409Pedido demasiado reciente para cancelar — espera 2 minutos
SERVICE_UNAVAILABLE503Servicio temporalmente no disponible (mantenimiento)