Documentación de la API
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:
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:
⟩ Formato de Respuesta
Cada respuesta devuelve JSON con una estructura consistente. Todas las respuestas incluyen un encabezado x-request-id para depuración.
{
"success": true,
"data": { ... }
} {
"success": false,
"error": {
"code": "ERROR_CODE",
"message": "Human-readable message"
}
} /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
{
"success": true,
"data": [
{
"id": 6,
"code": "ID",
"name": "Indonesia",
"dial_code": "+62",
"emoji": "🇮🇩",
"active": true
}
]
} /catalog/services Devuelve una lista de servicios (plataformas) disponibles. Opcionalmente filtra por país.
Parámetros de Consulta
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
country_id | integer | No | Filtrar 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
{
"success": true,
"data": [
{
"id": 3,
"code": "wa",
"name": "WhatsApp",
"active": true
}
]
} /catalog/products Devuelve una lista paginada de productos disponibles. Filtra por país y/o plataforma.
Parámetros de Consulta
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
country_id | integer | No | Filtrar por ID de país |
platform_id | integer | No | Filtrar por ID de plataforma/servicio |
sort | string | No | Orden de clasificación: price_asc (predeterminado), price_desc, available_asc, available_desc, name_asc, name_desc |
limit | integer | No | Resultados por página (1-10.000, predeterminado 1.000) |
page | integer | No | Nú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
{
"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 }
} /catalog/exchange-rate Devuelve la tasa de cambio actual para un par de divisas. Útil para convertir precios.
Parámetros de Consulta
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
pair | string | No | Par 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
{
"success": true,
"data": {
"pair": "USD/IDR",
"base_currency": "USD",
"quote_currency": "IDR",
"rate": 16250
}
} /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
{
"success": true,
"data": {
"currency": "IDR",
"balance": 500000
}
} /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
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
limit | integer | No | Máximo de resultados (1-100, predeterminado 20) |
offset | integer | No | Número de resultados a omitir (predeterminado 0) |
status | string | No | Filtrar 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
{
"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
}
]
} /orders/{id} Devuelve un pedido individual por ID. Solo devuelve pedidos del usuario autenticado.
Parámetros de Ruta
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
id | integer | Sí | ID 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
{
"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
}
} /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
{
"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
}
]
} /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
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
product_id | integer | Sí | ID del producto a pedir |
quantity | integer | No | Cantidad 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
{
"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
}
} /orders/cancel Cancela un pedido activo. El costo del alquiler se reembolsa al saldo de tu cuenta.
Cuerpo de la Solicitud
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
id | integer | Sí | ID 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
{
"success": true,
"data": {
"order_id": 1001,
"status": "CANCELED",
"refund_amount": 15000,
"new_balance": 515000
}
} /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
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
id | integer | Sí | ID 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
{
"success": true,
"data": {
"order_id": 1001,
"status": "COMPLETED"
}
} /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
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
id | integer | Sí | ID 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
{
"success": true,
"data": {
"order_id": 1001,
"status": "ACTIVE",
"resent": true
}
} /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
{
"success": true,
"data": {
"webhook_url": "https://example.com/webhook",
"webhook_secret": "a1b2c3d4e5f6..."
}
} /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
| Nombre | Tipo | Requerido | Descripción |
|---|---|---|---|
webhook_url | string | No | URL HTTPS para recibir eventos webhook (cadena vacía para borrar) |
webhook_secret | string | No | Secreto 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
{
"success": true,
"data": {
"webhook_url": "https://example.com/webhook",
"webhook_secret": "a1b2c3d4e5f6..."
}
} /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
{
"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
| Evento | Disparador |
|---|---|
order.otp_received | Código OTP entregado al número alquilado |
order.completed | Pedido marcado como completado (manual o por expiración) |
order.expired | Pedido expirado sin OTP (saldo reembolsado) |
order.canceled | Pedido cancelado por el usuario (saldo reembolsado) |
Payload
{
"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:
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 Endpoints | Límite | Ventana |
|---|---|---|
| Catálogo (países, servicios, productos, tasa de cambio) | 1.200 solicitudes | 60 segundos |
| Saldo | 600 solicitudes | 60 segundos |
| Lectura de pedidos (listar, obtener, activos) | 1.200 solicitudes | 60 segundos |
| Crear pedido | 1.200 solicitudes | 60 segundos |
| Cancelar pedido | 600 solicitudes | 60 segundos |
| Acciones de pedido (finalizar, reenviar) | 600 solicitudes | 60 segundos |
| Configuración de webhook (obtener, actualizar, probar) | 120 solicitudes | 60 segundos |
⟩ Códigos de Error
Las respuestas de error incluyen uno de estos códigos en error.code:
| Código | HTTP | Descripción |
|---|---|---|
UNAUTHORIZED | 401 | Token de la API faltante o inválido |
FORBIDDEN | 403 | Acceso denegado |
NOT_FOUND | 404 | Recurso no encontrado (pedido, tasa de cambio, etc.) |
CONFLICT | 409 | Solicitud duplicada o conflicto de recursos |
INSUFFICIENT_BALANCE | 409 | Saldo insuficiente para crear el pedido |
VALIDATION_ERROR | 422 | Los parámetros de la solicitud no pasaron la validación |
RATE_LIMIT_EXCEEDED | 429 | Demasiadas solicitudes (verifica el encabezado Retry-After) |
INTERNAL_ERROR | 500 | Error interno del servidor |
PROVIDER_ERROR | 422 | El proveedor SMS ascendente rechazó la solicitud |
CANCEL_TOO_EARLY | 409 | Pedido demasiado reciente para cancelar — espera 2 minutos |
SERVICE_UNAVAILABLE | 503 | Servicio temporalmente no disponible (mantenimiento) |