Desarrolladores
Documentación API
Consulta tu saldo y el precio en tiempo real de cualquier servicio en cualquier país desde tu propio código. Una clave Bearer, JSON sobre HTTPS, sin SDK que instalar.
Primeros pasos #
Todo es JSON sobre HTTPS, autenticado con una única clave que tú mismo creas. No hay que instalar ningún SDK, ni firmar ningún contrato, ni pedir un sandbox — basta con una clave y curl.
- 1 Crear clave Abre el menú de la cuenta, luego Clave de API, luego Crear clave. Se muestra una sola vez: solo guardamos su huella, así que después no se puede volver a consultar.
- 2 Envíala como token portador Cada solicitud lleva un encabezado Authorization. No hay otra forma de entrar — sin clave en la cadena de consulta, sin cookie, sin sesión.
- 3 Lee la respuesta Cada respuesta es un objeto JSON con un campo ok. Cuando ok es false, un campo error explica por qué con una cadena estable legible por máquina.
Autenticación #
Una clave por cuenta. Enviarla de cualquier otra forma que no sea el encabezado de abajo no está soportado — una clave en la cadena de consulta termina en los registros del servidor, el historial del navegador y los encabezados de referencia, así que se rechaza en lugar de aceptarse en silencio.
Authorization: Bearer sk_your_key_here
Una clave gasta dinero Hoy lee el saldo, y es la misma clave con la que se pedirán números cuando esa función exista. Trátala como una contraseña: fuera del control de versiones, fuera de las capturas de pantalla, se reemplaza en lugar de compartirse. Reemplazar una clave cierra la anterior de inmediato.
Convenciones #
| Dirección base | https://simsms.com/api/v1 |
|---|---|
| Transporte | Solo HTTPS. El HTTP simple se redirige, y la redirección no lleva tu encabezado. |
| Formato | JSON de entrada, JSON de salida. Cada respuesta es un objeto, nunca un array simple. |
| Éxito | HTTP 200 con "ok": true. |
| Fallo | Un código 4xx o 5xx con "ok": false y una cadena "error" estable. |
| Dinero | Los valores están en dólares estadounidenses, nunca como cadenas de texto, nunca en centavos. 0.84 significa 84 centavos. |
| Campos desconocidos | Cualquier respuesta puede incluir campos nuevos. Ignora lo que no conozcas en vez de fallar por ello. |
Errores #
La cadena error es la parte sobre la que debe decidir tu código. La frase que la acompaña es para ti, no para tu código — puede reformularse; la cadena no.
| HTTP | error | Caso |
|---|---|---|
| 401 | missing_key |
Falta el encabezado Authorization, o no es un token portador. |
| 401 | bad_key |
La clave es desconocida, o fue cerrada o reemplazada. |
| 400 | unknown_service |
No hay ningún servicio con ese código. Los códigos vienen del catálogo, no del nombre mostrado. |
| 404 | no_stock |
Ese par de servicio y país no tiene ningún número en stock ahora mismo. Es una cifra en vivo: puede recuperarse. |
| 404 | unknown_country |
No hay ningún país con ese código en ese producto. Los catálogos de proxy y de alquiler cubren cada uno su propia lista — llama a la ruta sin país para obtenerla. |
| 400 | unknown_tech |
No existe esa generación de red en ese país. Solo Estados Unidos vende tanto 4g como 5g. |
| 429 | rate_limited |
Demasiadas solicitudes. Un encabezado Retry-After indica cuántos segundos esperar. |
Límites de tasa #
600 solicitudes por minuto, contadas por cuenta y no por dirección. Una clave está pensada para ejecutarse desde un servidor — una sola dirección — así que un límite por dirección castigaría el uso normal y dejaría que una clave robada actuara libremente en otro lugar. Por encima del límite recibes un 429 y un encabezado Retry-After en segundos.
Rutas #
Lecturas de cuenta y catálogo. Cada ruta indica todos los parámetros que admite, todos los campos que devuelve y todos los errores con los que puede responder — nada de comportamiento sin documentar.
Consulta tu saldo #
GET
/api/v1/balance
Lo que la cuenta tiene ahora mismo, y cuántos códigos compra eso al precio más barato del catálogo en este momento.
Campos devueltos
| Campo | Tipo | Descripción |
|---|---|---|
ok |
boolean | Siempre true en un 200. |
balance |
number | Dólares disponibles, redondeados al centavo. |
currency |
string | Siempre "USD". Presente para que nunca tengas que suponerlo. |
codes_at_cheapest |
integer | Cuántos códigos compra el saldo al precio más barato del catálogo. Una estimación aproximada, no una cotización — null si el catálogo está vacío. |
cheapest_code |
number | Ese precio más barato, para que puedas calcular tú mismo la estimación con otra cifra. |
Petición
curl -s "https://simsms.com/api/v1/balance" \
-H "Authorization: Bearer $SIMSMS_KEY"
Respuesta
{
"ok": true,
"balance": 42.5,
"currency": "USD",
"codes_at_cheapest": 425,
"cheapest_code": 0.1
}
Puede responder missing_key bad_key rate_limited
Precio de un servicio en un país #
GET
/api/v1/pricing?service={service}&country={country}
El precio y el stock en vivo de un solo par. Ambas cifras cambian — el precio sigue a la red más barata que ofrece ese servicio en ese país, y el stock es lo que la red reporta ahora mismo.
Parámetros
| Parámetro | Descripción | |
|---|---|---|
service |
requerido | Código de servicio, por ejemplo telegram. En minúsculas, del catálogo. |
country |
opcional | Código de país, por ejemplo england. Omítelo para obtener todos los países a la vez — mira más abajo. |
Campos devueltos
| Campo | Tipo | Descripción |
|---|---|---|
ok |
boolean | Siempre true en un 200. |
service |
string | El código de servicio que pediste, devuelto tal cual. |
country |
string | El código de país que pediste, devuelto tal cual. |
price |
number | Dólares por un código, en la red más barata que lo tiene. |
stock |
integer | Líneas reportadas disponibles ahora mismo. Es una cifra en vivo y cambia. |
Petición
curl -s "https://simsms.com/api/v1/pricing?service=telegram&country=england" \
-H "Authorization: Bearer $SIMSMS_KEY"
Respuesta
{
"ok": true,
"service": "telegram",
"country": "england",
"price": 0.84,
"stock": 61213
}
Puede responder missing_key bad_key unknown_service no_stock rate_limited
Precio de un servicio en todas partes #
GET
/api/v1/pricing?service={service}
Omite el país y obtienes todos los países que ofrecen el servicio. El orden es el propio del sitio: lo que realmente entrega primero, y dentro de eso, lo más barato — no el precio bruto, que pondría arriba un número de dos centavos del que nadie recibe un código.
Parámetros
| Parámetro | Descripción | |
|---|---|---|
service |
requerido | Código de servicio, por ejemplo telegram. |
Campos devueltos
| Campo | Tipo | Descripción |
|---|---|---|
ok |
boolean | Siempre true en un 200. |
service |
string | El código de servicio que pediste. |
name |
string | Su nombre visible, por ejemplo «Telegram». |
countries |
array | Un objeto por país, en el orden descrito arriba. |
countries[].country |
string | Código de país, que se reutiliza en la llamada de emparejamiento. |
countries[].name |
string | Nombre en inglés. |
countries[].price |
number | Dólares por un código. |
countries[].stock |
integer | Números disponibles ahora mismo. |
Petición
curl -s "https://simsms.com/api/v1/pricing?service=telegram" \
-H "Authorization: Bearer $SIMSMS_KEY"
Respuesta
{
"ok": true,
"service": "telegram",
"name": "Telegram",
"countries": [
{ "country": "england", "name": "United Kingdom", "price": 0.84, "stock": 61213 },
{ "country": "poland", "name": "Poland", "price": 0.91, "stock": 22140 }
]
}
Puede responder missing_key bad_key unknown_service rate_limited
Precio de proxy móvil #
GET
/api/v1/proxy-pricing?country={country}&tech={tech}
Sin país, obtienes los cuatro países donde tenemos módems, con su número de operadores y el precio de entrada. Con uno, cada operador allí y el precio de cada duración. Las duraciones están en días: 1, 7, 30, 365.
Parámetros
| Parámetro | Descripción | |
|---|---|---|
country |
opcional | Código de país, por ejemplo us. Omítelo para ver la lista de países. |
tech |
opcional | Generación de red, 4g o 5g. Solo Estados Unidos vende las dos; en el resto se ignora el campo y se devuelve el único rango. |
Campos devueltos
| Campo | Tipo | Descripción |
|---|---|---|
ok |
boolean | Siempre true en 200. |
country |
string | El país que has pedido. |
tech |
string | La generación que realmente se ha usado para calcular el precio, una vez aplicado el valor por defecto. |
techs |
array | Todas las generaciones que se venden en ese país. |
terms |
array | Las duraciones a la venta, en días. |
carriers |
array | Un objeto por operador. |
carriers[].carrier |
string | Código de operador, para usar en el pedido. |
carriers[].name |
string | Su nombre visible, por ejemplo «T-Mobile». |
carriers[].prices |
object | Dólares por duración, según el número de días. |
Petición
curl -s "https://simsms.com/api/v1/proxy-pricing?country=us" \
-H "Authorization: Bearer $SIMSMS_KEY"
Respuesta
{
"ok": true,
"country": "us",
"tech": "4g",
"techs": ["4g", "5g"],
"terms": [1, 7, 30, 365],
"carriers": [
{ "carrier": "us-t-mobile", "name": "T-Mobile", "prices": { "1": 8.67, "7": 52, "30": 130, "365": 1300 } },
{ "carrier": "us-verizon", "name": "Verizon", "prices": { "1": 8.67, "7": 52, "30": 130, "365": 1300 } }
]
}
Puede responder missing_key bad_key unknown_country unknown_tech rate_limited
Precio de alquiler #
GET
/api/v1/rental-pricing?country={country}&days={days}
Sin país, obtienes todos los países donde se puede mantener un número, con su precio de entrada. Con uno, cada operador allí y lo que cuesta la duración que has pedido.
Parámetros
| Parámetro | Descripción | |
|---|---|---|
country |
opcional | Código de país, por ejemplo fr. Omítelo para ver la lista de países. |
days |
opcional | Duración en días: 7, 14 o 30. Cualquier otro valor usa la más corta por defecto. |
Campos devueltos
| Campo | Tipo | Descripción |
|---|---|---|
ok |
boolean | Siempre true en 200. |
country |
string | El país que has pedido. |
days |
integer | La duración que realmente se ha usado para calcular el precio. |
terms |
array | Todas las duraciones a la venta, en días. |
operators |
array | Un objeto por operador, el más barato primero. |
operators[].operator |
string | Código de operador, para usar en el pedido. |
operators[].name |
string | Su nombre visible. |
operators[].type |
string | físico, virtual o premium. |
operators[].price |
number | Dólares por toda la duración. |
Petición
curl -s "https://simsms.com/api/v1/rental-pricing?country=fr&days=30" \
-H "Authorization: Bearer $SIMSMS_KEY"
Respuesta
{
"ok": true,
"country": "fr",
"days": 30,
"terms": [7, 14, 30],
"operators": [
{ "operator": "fr-lycamobile", "name": "Lycamobile", "type": "virtual", "price": 14.32 },
{ "operator": "fr-orange", "name": "Orange", "type": "physical", "price": 20.76 }
]
}
Puede responder missing_key bad_key unknown_country rate_limited
Ejemplos #
Programas completos y ejecutables, no fragmentos de una línea — incluidas las dos cosas que los fragmentos siempre omiten: gestionar la forma del error y aplicar espera progresiva ante un 429.
Shell #
Encuentra el país más barato para un servicio y luego comprueba que el saldo lo cubre.
#!/usr/bin/env bash
set -euo pipefail
: "${SIMSMS_KEY:?export your key first}"
API="https://simsms.com/api/v1"
auth=(-H "Authorization: Bearer $SIMSMS_KEY")
# The catalogue is already ordered: the first country is the one to take.
best=$(curl -sf "${API}/pricing?service=telegram" "${auth[@]}" \
| jq -r ".countries[0] | \"\(.country) \(.price)\"")
country=${best% *}
price=${best#* }
balance=$(curl -sf "${API}/balance" "${auth[@]}" | jq -r .balance)
# ⚠️ Compare as numbers, not as strings: "9.5" > "10" is true in a string sort.
if awk "BEGIN{exit !($balance >= $price)}"; then
echo "ok: $country at \$$price, balance \$$balance"
else
echo "top up first: need \$$price, have \$$balance" >&2
exit 1
fi
JavaScript #
Lo mismo en Node, con el formato de error bien gestionado.
const API = "https://simsms.com/api/v1";
const key = process.env.SIMSMS_KEY;
async function call(path) {
const r = await fetch(API + path, {
headers: { Authorization: `Bearer ${key}` },
});
const body = await r.json();
// A non-2xx always carries { ok:false, error }. Branch on `error`, never on
// the sentence — the string is stable, the wording is not.
if (!r.ok || !body.ok) {
if (body.error === "rate_limited") {
const wait = Number(r.headers.get("Retry-After") || 60);
await new Promise((s) => setTimeout(s, wait * 1000));
return call(path);
}
throw new Error(body.error ?? `http_${r.status}`);
}
return body;
}
const { countries } = await call("/pricing?service=telegram");
const { balance } = await call("/balance");
const best = countries[0];
console.log(`${best.name}: $${best.price} (${best.stock} in stock)`);
console.log(balance >= best.price ? "balance covers it" : "top up first");
Python #
Y en Python, con el mismo reintento en el 429.
import os, time, requests
API = "https://simsms.com/api/v1"
S = requests.Session()
S.headers["Authorization"] = f"Bearer {os.environ['SIMSMS_KEY']}"
def call(path):
r = S.get(API + path, timeout=20)
body = r.json()
if not r.ok or not body.get("ok"):
if body.get("error") == "rate_limited":
time.sleep(int(r.headers.get("Retry-After", 60)))
return call(path)
raise RuntimeError(body.get("error", f"http_{r.status_code}"))
return body
countries = call("/pricing?service=telegram")["countries"]
balance = call("/balance")["balance"]
best = countries[0]
print(f"{best['name']}: ${best['price']} ({best['stock']} in stock)")
print("balance covers it" if balance >= best["price"] else "top up first")
Planes #
La API cubre hoy las lecturas de cuenta y catálogo. Los pedidos llegan después, bajo la misma dirección base y la misma clave: nada de lo que construyas ahora necesitará reescribirse.
| Pedir un número | Previsto Previsto. Por ahora, los pedidos se hacen desde el sitio. |
|---|---|
| Consultar el código | Previsto Previsto, junto con los pedidos. |
| Liberar un número | Previsto Previsto, junto con los pedidos. |
| Alquiler por API | Previsto Previsto. |
| Webhooks | Previsto Previsto, cuando haya eventos de pedidos que entregar. |
Esta página crece con ellos: las secciones de abajo se quedan donde están, y las nuevas se añaden bajo Endpoints.
Cambios #
- Primera versión pública: claves, GET /balance, GET /pricing.