Documentación

Documentación de la API

Todo lo que hace el panel está disponible por HTTP. Apunta un panel SMM a un único endpoint, o controla toda la plataforma — catálogo, campañas, registros, facturas — desde un script o un agente de IA.

En esta página

Descripción general

Toplistbot expone dos APIs HTTP. Ambas son JSON sobre HTTPS, ambas gastan el mismo saldo de tokens, y cualquiera de las dos basta para lanzar campañas sin abrir nunca el panel.

URL base

Base URL
https://backend.toplistbot.com/api
https://backend.toplistbot.com

La referencia siguiente está escrita contra estos dos hosts. El que uses decide cómo te autenticas — consulta Autenticación.

Primeros pasos

De una cuenta nueva a una campaña en marcha en cinco pasos. Todo lo de abajo usa el endpoint SMM, la vía más rápida; la API de la plataforma funciona igual una vez que tengas un JWT.

  1. Crea una cuenta

    Regístrate y verifica tu correo. La verificación abona 100 tokens gratis en tu saldo, suficiente para lanzar una campaña real antes de gastar nada.

  2. Copia tu clave de API

    Abre tu panel y genera una clave de API. Trátala como una contraseña: gasta tu saldo de tokens. Puedes regenerarla cuando quieras, lo que invalida la anterior al instante.

  3. Encuentra el servicio que quieres

    Lista todos los sitios en los que puedes hacer pedidos. Cada entrada tiene un id numérico de servicio y una tarifa en tokens por cada 1.000 acciones. Anota el id del sitio en el que quieres promocionar.

    cURL
    curl -X POST https://backend.toplistbot.com/api/v2 -d "key=YOUR_API_KEY" -d "action=services"
  4. Haz tu primer pedido

    Envía el id del servicio, la URL sobre la que se ejecuta la campaña y cuántas acciones lanzar. El coste se descuenta al momento y la respuesta te da un id de pedido.

    cURL
    curl -X POST https://backend.toplistbot.com/api/v2 \
      -d "key=YOUR_API_KEY" \
      -d "action=add" \
      -d "service=9" \
      -d "link=https://arena-top100.com/index.php?a=in&u=yourserver" \
      -d "quantity=1000"
  5. Sigue la entrega

    Consulta el id del pedido para ver cuánto se ha entregado. Cuando el flujo te convenza, conecta las mismas llamadas a tu propio panel o a tus scripts.

    cURL
    curl -X POST https://backend.toplistbot.com/api/v2 -d "key=YOUR_API_KEY" -d "action=status" -d "orders=184223"

Conectar una instancia de Perfect Panel

Si usas Perfect Panel o software de panel SMM compatible, no necesitas escribir código: añade Toplistbot como proveedor con estos ajustes e importa la lista de servicios.

URL de la API
https://backend.toplistbot.com/api/v2
Clave de API
YOUR_API_KEY
Método HTTP
POST

Empieza con una cantidad pequeña en un solo sitio para confirmar que se acepta el formato de tu enlace antes de aumentar el volumen. Un enlace incorrecto también consume tokens.

Automatizar con un agente de IA

Esta página tiene un gemelo en texto plano escrito para máquinas. Dale esa URL a un agente junto con tu clave API y tendrá todo lo necesario: la lista completa de endpoints, las formas de petición y respuesta, la aritmética de precios, los códigos de error y ejemplos completos.

Referencia legible por máquinas

Un solo documento, sin autenticación y sin JavaScript. Descárgalo, pégalo en un prompt o pasa la URL a una herramienta que sepa navegar.

https://toplistbot.com/llms.txt

Prompt inicial

Pega esto en Claude o en cualquier agente capaz de hacer peticiones HTTP. Guarda la clave en una variable de entorno en lugar de escribirla en el mensaje.

Prompt
Read https://toplistbot.com/llms.txt — it is the complete Toplistbot API reference.

My API key is in the TOPLISTBOT_KEY environment variable. Using the API-key
surface (paths without the /api prefix):

  1. list the sites in the catalog that cost under 20 tokens per 1,000 votes
  2. tell me my token balance
  3. propose a campaign for <my vote URL> that fits a budget of <N> tokens

Do not place the order until I confirm the cost.

Una clave API es la credencial adecuada para un agente: no caduca, no le afecta la autenticación en dos pasos y rotarla desde el panel revoca el acceso al instante si alguna vez lo necesitas.

Autenticación

Hay dos credenciales, y cuál necesitas depende de la ruta más que del endpoint. Casi todos los endpoints están montados dos veces.

El prefijo /api decide la credencial

El mismo manejador atiende ambas rutas. Quita el prefijo /api y la API de plataforma acepta una clave API de larga duración; mantenlo y el endpoint espera un JWT obtenido al iniciar sesión.

RutaCredencialÚsala para
/api/orders/getAllJWTCualquier cosa donde una persona inicie sesión
/orders/getAllClave APIScripts, tareas programadas, agentes

Para automatizar, usa mejor las rutas sin prefijo. No hay inicio de sesión, ni caducidad, ni sesión que mantener viva — una sola clave lo hace todo, y la autenticación en dos pasos nunca se interpone.

Clave API

Envía tu clave como campo `key` en cualquier petición: parámetro de consulta, campo de formulario, campo JSON o cabecera `Authorization: Bearer`. Genérala y rótala desde el panel. Un GET a /api/v2 devuelve un estado ok y es una forma barata de comprobar que la clave sigue viva.

cURL
# any of these three carry the key
curl "https://backend.toplistbot.com/orders/getAll?key=YOUR_API_KEY"
curl -X POST https://backend.toplistbot.com/orders/pause -d "key=YOUR_API_KEY" -d "id=184223"
curl https://backend.toplistbot.com/orders/getAll -H "Authorization: Bearer YOUR_API_KEY"
Health check
curl https://backend.toplistbot.com/api/v2?key=YOUR_API_KEY

JWT

Inicia sesión para recibir un token y envíalo como bearer token en las rutas /api. Los tokens caducan, así que llama a /auth/refresh antes de que lo hagan. Si la cuenta tiene la autenticación en dos pasos activada, el inicio de sesión también necesita `two_factor_code`.

Login
curl -X POST https://backend.toplistbot.com/api/auth/login \
  -H "Content-Type: application/json" \
  -d '{"email":"[email protected]","password":"..."}'
Response
{
  "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9...",
  "token_type": "bearer",
  "expires_in": 3600,
  "user": { "id": 4211, "email": "[email protected]", "tokens": 528.41, "...": "..." }
}
Authenticated request
curl https://backend.toplistbot.com/api/orders/getAll \
  -H "Authorization: Bearer YOUR_JWT"

Llamar desde un navegador

Todas las rutas responden con Access-Control-Allow-Origin abierto, así que una página, una extensión del navegador o un agente que corra en el navegador pueden llamar a la API directamente, sin que montes un proxy propio. La advertencia de arriba sigue en pie: una clave que envías al navegador es una clave que has publicado, así que esto es para tus propias herramientas, no para una página pública.

JavaScript
// Works from a page, an extension, or a browser-based agent.
const sites = await fetch(
  'https://backend.toplistbot.com/orders/getAllWebsites'
).then(r => r.json())

Tu clave API gasta saldo real de tokens. Mantenla en el servidor: cualquier clave enviada a un navegador o subida a un repositorio debe considerarse comprometida y rotarse desde el panel.

Tokens y precios

Las campañas se pagan en tokens, comprados por adelantado. Cada sitio publica una tarifa —cuántos tokens cuesta lanzar 1.000 acciones de campaña allí— que la acción services devuelve como `rate`.

Cost formula
cost_in_tokens = (rate * quantity) / 1000

Un sitio con tarifa 13 cuesta 13 tokens por 1.000 acciones, así que un pedido de 500 cuesta 6,5 tokens. El coste se descuenta al aceptar el pedido, y cancelar devuelve el resto no gastado.

Las respuestas de balance y status indican un campo de moneda USD por compatibilidad con Perfect Panel, pero el valor es un saldo de tokens, no dólares. Trata el número como tokens.

API de panel SMM

Un solo endpoint lo hace todo. Envía un campo `action` en cada POST para elegir la operación; toda petición lleva además tu `key`.

POSThttps://backend.toplistbot.com/api/v2
AcciónParámetros
services
addservice, link, quantity, interval?
statusorders
balance
cancelorders

`refill` y `refill_status` se aceptan por compatibilidad y ambas responden "no implementado". Aquí nada es recargable; vuelve a pedir en su lugar.

action=services

Lista todos los sitios en los que puedes hacer pedidos, con su tarifa actual y sus límites. Usa el id `service` en tus llamadas add.

cURL
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=services"
Response
[
  {
    "service": 9,
    "name": "arena-top100.com 1000 upvotes",
    "type": "Default",
    "category": "Votes",
    "rate": 15,
    "min": 1,
    "max": 50000,
    "refill": false,
    "cancel": true
  }
]

`rate` va en tokens por cada 1.000 acciones. `min` es 1 y `max` es 50000 en todos los servicios.

action=add

Crea una campaña y descuenta su coste de tu saldo de inmediato.

ParámetroTipoDescripción
keyobligatoriostringTu clave de API.
actionobligatoriostringDebe ser `add`.
serviceobligatoriointegerId de servicio de la acción services.
linkobligatoriourlLa URL sobre la que se ejecuta la campaña. Debe ser una URL válida.
quantityobligatoriointegerNúmero de acciones a lanzar, entre 1 y 50000.
intervalintegerAcciones por hora. Por defecto 15, con tope de 4000, y no puede superar el máximo propio del sitio.
cURL
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=add" \
  -d "service=9" \
  -d "link=https://arena-top100.com/index.php?a=in&u=yourserver" \
  -d "quantity=1000" \
  -d "interval=60"
Response
{
  "order_id": 184223
}

action=status

Devuelve el progreso de uno o varios pedidos. Pasa un solo id para obtener un objeto simple, o una lista separada por comas.

cURL
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=status" \
  -d "orders=184223"
Response — single order
{
  "charge": 13.5,
  "start_count": 0,
  "status": "Completed",
  "remains": 1000,
  "currency": "USD"
}

Con varios ids la respuesta se indexa por id de pedido, y los pedidos desconocidos o ajenos devuelven una entrada de error en lugar de hacer fallar toda la petición.

Response — multiple orders
{
  "184223": { "charge": 13.5, "start_count": 0, "status": "Completed", "remains": 1000, "currency": "USD" },
  "184224": { "error": "Incorrect order ID" }
}

Lee `remains`, no `status`

`status` siempre vale literalmente "Completed". El campo existe porque todo cliente Perfect Panel lo exige, y los paneles tratan cualquier otro valor como candidato a recarga, algo que esta plataforma no ofrece. El progreso está en los números: `remains` son los votos aceptados que quedan por entregar, así que `remains == 0` significa que el pedido ha terminado. `start_count` es lo entregado hasta ahora y `charge` lo que ha costado. Ambos se miden contra la tasa de aceptación del sitio, así que cuentan los votos que compraste y no los intentos en bruto.

`status` y `cancel` aceptan como máximo 100 ids de pedido por llamada. Agrupa en lugar de iterar: una llamada con 100 ids es mucho más barata para ambas partes que 100 llamadas.

action=balance

Devuelve tu saldo restante de tokens.

cURL
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=balance"
Response
{
  "balance": 528.41,
  "currency": "USD"
}

action=cancel

Detiene un pedido y devuelve el resto no gastado a tu saldo. Los pedidos completados no se pueden cancelar.

cURL
curl -X POST https://backend.toplistbot.com/api/v2 \
  -d "key=YOUR_API_KEY" \
  -d "action=cancel" \
  -d "orders=184223,184224"
Response
[
  { "order": "184223", "cancel": 1, "refund": 4.5 },
  { "order": "184224", "cancel": { "error": "Incorrect order ID" } }
]

API de la plataforma

La misma API REST que usa el panel. Las rutas de abajo están escritas en su forma con clave API, sin el prefijo /api. Añade /api y cambia la clave por un JWT para usar la forma con sesión; los endpoints marcados como JWT solo existen bajo /api.

Catálogo y descubrimiento

Público, sin credencial. getAllWebsites es el endpoint por el que empezar: trae el id, el precio, el techo por hora y la tasa de aceptación que necesitas para calcular el precio y dar forma a un pedido.

  • GET/orders/getAllWebsitesPúblicaEl catálogo completo: cada sitio con tarifas, límites y metadatos
  • GET/orders/getAllBasicWebsitesDetailsPública20 nombres de sitio al azar, para widgets y autocompletados
  • POST/orders/getWebsiteDetailsByNamePúblicaUn sitio por su nombre exacto
  • POST/products/getSuggestionsPúblicaSitios relacionados con un conjunto de ids
  • GET/products/demand?days=30PúblicaCuánto se ha pedido cada sitio últimamente
  • GET/products/tokensPúblicaPaquetes de tokens que puedes comprar
  • POST/products/suggestClave APIPídenos que añadamos un sitio nuevo
  • GET/api/news/timelinePúblicaNovedades del producto
cURL
curl "https://backend.toplistbot.com/orders/getAllWebsites"

Pide menos

El catálogo completo pesa unos 665 KB repartidos en 396 sitios, y dos campos con los que nunca vas a pedir son la mitad de ese peso: un bloque JSON de popularidad y la descripción de marketing. Proyecta solo los campos que usas para pedir y descarta los sitios inactivos y se queda en unos 40 KB.

cURL + jq
# The whole catalog is ~665 KB across 396 sites.
# Projected to what you actually order with: ~40 KB.
curl -s "https://backend.toplistbot.com/orders/getAllWebsites" \
  | jq '[.[]
      | select(.active == 1)
      | {id, name, price_per_1000, max_per_hour, accept_rate, subscribeable}]'

Para un agente de IA esa es la diferencia entre unos 170.000 tokens y 10.000: entre que la primera llamada funcione o que agote la ventana de contexto. Proyecta antes de analizar.

Cuenta y sesiones

El registro necesita un navegador: está protegido por un desafío de Cloudflare. Regístrate una vez en app.toplistbot.com y automatiza todo lo demás.

  • POST/api/auth/registerPúblicaCrear una cuenta: solo por navegador, protegido por captcha
  • POST/api/auth/loginPúblicaCambiar credenciales por un JWT
  • POST/api/auth/refreshJWTEmitir un JWT nuevo a partir de uno que caduca
  • POST/api/auth/logoutJWTInvalidar el JWT actual
  • GET/api/auth/user-profileJWTLa cuenta conectada, con saldo y clave API
  • GET/api/userJWTEl mismo objeto de usuario, en una ruta más corta
  • GET/api/api_tokenClave APIResolver una clave API a su dueño: úsalo para validar una clave
  • POST/api/auth/reset-api-keyJWTRotar tu clave API; la anterior muere al instante
  • POST/api/auth/fingerprintJWTRegistrar una huella de navegador en la cuenta
  • POST/api/auth/ipJWTRegistrar la IP actual de la cuenta
  • POST/api/auth/forgot-passwordPúblicaEnviar por correo un enlace de restablecimiento, válido 60 minutos
  • POST/api/auth/reset-passwordPúblicaFijar una contraseña nueva con el token enviado por correo

Doble factor e inicio de sesión

El doble factor protege el inicio de sesión con contraseña. No se aplica a las claves API, y por eso una clave es la mejor credencial para trabajo desatendido.

  • POST/api/2fa/enableJWTIniciar el alta: devuelve el secreto, la URL del QR y los códigos de recuperación
  • POST/api/2fa/verifyJWTConfirmar un código de seis dígitos y activar el doble factor
  • POST/api/2fa/disableJWTDesactivar el doble factor
  • POST/api/account/verification/requestJWTEnviar un enlace de verificación a la dirección conectada
  • GET/api/account/verification/confirm?token=PúblicaMostrar la página de confirmación: no escribe nada
  • POST/api/account/verification/confirmPúblicaConfirmar la verificación
  • GET/api/auth/googlePúblicaIniciar sesión con Google
  • GET/api/auth/google/callbackPúblicaRetorno del inicio de sesión con Google
  • GET/api/auth/discordPúblicaIniciar sesión con Discord
  • GET/api/auth/discord/callbackPúblicaRetorno del inicio de sesión con Discord

Preferencias y avisos

Interruptores de correo y notificaciones, y el historial de avisos de la cuenta.

  • GET/api/user/email-preferencesJWTEstado de suscripción a correos de marketing
  • POST/api/user/email-preferencesJWTCambiarlo
  • GET/api/user/notification-preferencesJWTPreferencia de avisos de voto en vivo
  • POST/api/user/notification-preferencesJWTCambiarlo: debe ser un booleano JSON real
  • GET/api/user/alerts?limit=20JWTAvisos de la cuenta, del más reciente al más antiguo, paginados con ?before
  • POST/api/user/alerts/readJWTMarcar un aviso como leído
  • POST/api/user/alerts/dismissJWTDescartar un aviso
  • GET/api/email/unsubscribe?token=PúblicaBaja en un clic desde un token enviado por correo

Campañas

Crear campañas, dirigirlas mientras corren y cerrarlas. Es el núcleo de la API de plataforma.

  • GET/orders/getAllClave APITus campañas, de la más reciente a la más antigua, con su sitio incluido
  • GET/orders/get/{id}Clave APIUna campaña
  • POST/orders/checkoutClave APICrear campañas y cobrar del saldo
  • POST/orders/updateClave APIEditar una campaña
  • POST/orders/pauseClave APIPausar una campaña en marcha
  • POST/orders/unpauseClave APIReanudar una campaña pausada
  • POST/orders/archiveClave APIArchivar una campaña
  • POST/orders/unarchiveClave APIRestaurar una campaña archivada
  • PATCH/orders/updateLimitClave APIFijar o quitar el tope diario de votos

POST /orders/checkout

El cuerpo es un array JSON de líneas de carrito en el nivel superior, no un objeto. Cada línea es una campaña. Todo el carrito se valida antes de cobrar nada, y el cobro y las inserciones son una sola transacción: un pedido ocurre entero o no ocurre.

Una línea de cantidad fija

El caso habitual: entregar un número concreto de votos a una URL.

ParámetroTipoDescripción
idobligatoriointegerId del sitio, de /orders/getAllWebsites.
amountobligatoriointegerVotos a entregar. 0 o más, hasta 2.147.483.647.
ownNameobligatoriourlLa URL de voto. Se guarda como el campo `url` del pedido.
custom_max_per_hourintegerTecho de entrega, limitado al máximo del propio sitio.
extra_colstringCampo de texto libre que viaja con el pedido.
cURL
curl -X POST "https://backend.toplistbot.com/orders/checkout?key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '[
    {
      "id": 9,
      "amount": 1000,
      "ownName": "https://arena-top100.com/index.php?a=in&u=yourserver",
      "custom_max_per_hour": 60
    }
  ]'
Response
200 OK
Successfully purchased with token balance

Una línea de suscripción

Para sitios cuyo indicador `subscribeable` vale 1. Se cobra a partir de subscription_price_1d del sitio multiplicado por los días y por el descuento del nivel: Weekly es 0,90, Monthly es 0,80 y cualquier otro es 1,00. La cantidad entregada se deriva en el servidor a partir del propio subscription_speed del sitio, así que nada de lo que envíes la cambia.

Body
[
  {
    "type": "subscription",
    "website": { "id": 9 },
    "subscription_days": 30,
    "tier": { "name": "Monthly" },
    "url": "https://arena-top100.com/index.php?a=in&u=yourserver"
  }
]

Respuestas

  • 200Todas las líneas se crearon y se cobró del saldo. El cuerpo es texto plano.
  • 400El cuerpo no era JSON válido.
  • 402Saldo insuficiente. El mensaje indica cuántos tokens faltan y no se cobró nada.
  • 422Una o más líneas están mal. No se cobró nada.
  • 429El mismo carrito se envió en los últimos 60 segundos. Reintenta tras la espera indicada.

Un 422 señala la línea culpable: los errores se indexan como items.[index].[field], así que un carrito con tres líneas malas se arregla en un viaje y no en tres.

422 body
{
  "errors": {
    "items.2.amount": ["Enter 0 or more votes; a negative amount is not allowed."]
  }
}

POST /orders/update

`id` es obligatorio; envía solo los campos que cambias. Los pedidos de suscripción no se pueden modificar.

ParámetroTipoDescripción
idobligatoriointegerLa campaña a editar.
amount_to_dointegerNuevo total de votos. Subirlo cobra la diferencia, bajarlo la devuelve, y hay 30 segundos de espera entre cambios.
urlurlLa URL de voto.
custom_namestringTu propia etiqueta para la campaña.
custom_max_per_hourintegerTecho de entrega.
username_profile_idintegerAsociar un perfil de voto.
proxy_profile_idintegerAsociar un perfil de proxy.
http_referralurlReferente a enviar con cada voto.
extra_colstringCampo de texto libre.
cURL
curl -X POST "https://backend.toplistbot.com/orders/update?key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"id":184223,"amount_to_do":2000,"custom_name":"EU launch"}'

Tope diario

`type: "delete"` quita el tope. En ese caso el validador sigue exigiendo `max_votes_per_day`: envía cualquier entero.

cURL
curl -X PATCH "https://backend.toplistbot.com/orders/updateLimit?key=YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"id":184223,"max_votes_per_day":500,"type":"set"}'

Registros y analíticas

Datos de entrega, voto a voto y agregados. Leen una base de datos de registros aparte y son más lentos que el resto de la API: consúltalos cada minutos, no cada segundos.

  • GET/orders/logs/{id}Clave APIRegistro de entrega voto a voto de una campaña
  • GET/orders/graph/{id}Clave APISerie temporal de una campaña, lista para graficar
  • GET/api/orders/graph/summaryJWTUna serie que agrupa todas tus campañas
  • GET/orders/grouped/usernames/{id}Clave APIEntregas agrupadas por el usuario que votó
  • POST/orders/averageClave APIEntrega media de varias campañas
  • GET/api/logs/{id}/filtered-graphJWTSerie temporal filtrada

Perfiles de voto y proxy

Un perfil de voto es una lista con nombre de usuarios con los que vota una campaña. Un perfil de proxy es una lista de países permitidos para las IP que usa. Asocia cualquiera de los dos a una campaña con username_profile_id o proxy_profile_id en /orders/update.

  • GET/advanced/profile/getClave APITus perfiles de voto
  • GET/advanced/profile/get/{id}Clave APIUn perfil de voto
  • POST/advanced/profile/createClave APICrear un perfil de voto, o sobrescribir uno por id
  • DELETE/advanced/profile/delete/{id}Clave APIBorrar un perfil de voto
  • GET/advanced/profile/proxy/getClave APITus perfiles de proxy
  • GET/advanced/profile/proxy/get/{id}Clave APIUn perfil de proxy
  • POST/advanced/profile/proxy/createClave APICrear un perfil de proxy, o sobrescribir uno por id
  • DELETE/advanced/profile/proxy/delete/{id}Clave APIBorrar un perfil de proxy

Tokens de Discord

Para listas que autentican a los votantes a través de Discord. Añadir el mismo token dos veces se rechaza como duplicado.

  • GET/api/discord-tokensJWTTus tokens de Discord
  • POST/api/discord-tokensJWTAñadir un token
  • GET/api/discord-tokens/statsJWTUso acumulado de tus tokens
  • GET/api/discord-tokens/{id}JWTUn token
  • PATCH/api/discord-tokens/{id}JWTCambiar un token o su estado activo
  • DELETE/api/discord-tokens/{id}JWTEliminar un token
  • PUT/api/discord-tokens/{id}/toggleJWTAlternar un token entre activo e inactivo

Facturación y pagos

Comprar tokens siempre termina en una página de pago alojada, así que recargar no puede ser totalmente automático. Todo lo posterior a la recarga sí.

  • GET/invoices/getClave APIHistorial de facturación
  • GET/api/subscriptions/subscriptionsJWTSuscripciones activas
  • GET/products/tokensByUserClave APIPaquetes de tokens con el precio de tu cuenta
  • POST/company/getClave APITu dirección de facturación
  • POST/company/createClave APIFijarla: country, region, city, address, postalCode
  • GET/api/stripe/checkout?product_id=JWTUna URL de Stripe Checkout para un paquete de tokens
  • GET/api/stripe/subscription?plan=JWTUna URL de Stripe Checkout para un plan
  • GET/api/stripe/portalJWTUna URL del portal de facturación de Stripe
  • GET/api/stripe/documentsJWTFacturas y recibos de Stripe
  • GET/coinpayments/checkoutClave APIUna URL de pago con criptomonedas

Carrito guardado

El carrito del panel, guardado en el servidor para que sobreviva a un cambio de dispositivo. No lo necesitas para crear pedidos: /orders/checkout acepta el carrito en la propia petición.

  • GET/api/cartJWTEl carrito guardado
  • PUT/api/cartJWTReemplazarlo
  • POST/api/cartJWTReemplazarlo, igual que PUT
  • DELETE/api/cartJWTVaciarlo

Superficies internas

Existen para Stripe, el planificador de tareas y el desafío antiabuso del registro. Se autentican con secretos compartidos o firmas y no forman parte de la superficie de integración: se listan aquí solo para que el inventario esté completo.

  • POST/api/stripe/webhookEventos de pago de Stripe, autenticados por firma
  • POST/api/jobs/tickEjecuta las tareas pendientes, autenticado por secreto compartido
  • POST/api/pow/challengeDesafío de prueba de trabajo del registro
  • POST/api/logs/updateSeguimiento de actividad de correo
  • POST/api/order/{email}Crea un pedido en otra cuenta: solo lista blanca de administradores
  • GET/reset-password/{token}La antigua página de restablecimiento renderizada en servidor, mantenida por los enlaces ya enviados
  • GET/PúblicaComprobación de estado

Formatos de respuesta

Casi todo lo que vas a leer viene en dos objetos: el sitio, que devuelven los endpoints del catálogo, y la campaña, que devuelven los de pedidos. Cada uno tiene unas cuarenta columnas; las tablas de abajo son las que de verdad necesita una integración.

Tres campos llegan como cadenas JSON aunque contengan números: accept_rate y timeout en el sitio, y custom_max_per_hour en la campaña. Conviértelos antes de hacer cuentas o acabarás concatenando cadenas en lugar de sumando.

Types to watch
{
  "accept_rate": "70",          // string, not number
  "timeout": "150000",          // string, not number
  "custom_max_per_hour": "60"   // string, not number
}

El objeto sitio

Lo devuelven /orders/getAllWebsites y /orders/getWebsiteDetailsByName, y viene incrustado en cada campaña como `website`.

ParámetroTipoDescripción
idintegerEl id del sitio. Se envía como `id` en una línea de carrito, o como `service` en el endpoint SMM.
namestringNombre visible, y la cadena exacta con la que compara /orders/getWebsiteDetailsByName.
price_per_1000numberTokens por cada 1.000 votos aceptados. Es el número que usa la fórmula de coste.
accept_ratestringPorcentaje de votos enviados que se aceptan. De él dependen todos los cálculos de progreso y de reembolso.
max_per_hourintegerEl techo de entrega del propio sitio. Tanto custom_max_per_hour como el interval del SMM se recortan a este valor.
activeinteger1 significa que se puede pedir. Los sitios inactivos también se devuelven, así que fíltralos tú.
vote_reset_timeintegerHoras que deben pasar antes de que la misma identidad pueda volver a votar.
speed_changeableinteger1 significa que el sitio respeta una velocidad de entrega personalizada.
referer_must_be_setinteger1 significa que hay que fijar http_referral en la campaña.
optional_data_possibleinteger1 significa que el sitio acepta el campo optional_data de la campaña.
track_votesinteger1 significa que hay registros de entrega voto a voto para las campañas de este sitio.
subscribeableinteger1 significa que se aceptan líneas de suscripción.
subscription_price_1dnumberTokens por día de suscripción, antes del descuento por nivel.
subscription_speedintegerVotos por hora que entrega una suscripción. La cantidad se deriva de aquí en el servidor, nunca de tu petición.

Los campos que no aparecen aquí alimentan la propia interfaz del panel. Léelos si quieres, pero no forman parte del contrato de integración y pueden cambiar sin aviso.

El objeto campaña

Lo devuelven /orders/getAll y /orders/get/. Fíjate en lo que falta: no hay campo de estado.

ParámetroTipoDescripción
idintegerEl id de la campaña. Todos los endpoints de Campañas lo reciben como `id`.
vote_website_idintegerEl sitio en el que corre esta campaña.
websiteobjectEl objeto sitio completo, incrustado. Está en /orders/getAll y no en /orders/get/.
urlstringLa URL de voto: el `ownName` que enviaste al crear el pedido.
custom_namestringTu propia etiqueta para la campaña, o null.
amount_to_dointegerVotos aceptados comprados. Cuenta votos aceptados, no intentos.
amount_doneintegerVotos enviados hasta ahora. Unidad distinta a amount_to_do: mira la sección de progreso.
runninginteger1 entregando, 0 en pausa.
doneinteger1 significa cerrada: cancelada, reembolsada y con ambas cantidades a cero. No es un indicador de finalización.
archiveinteger1 significa archivada. Las campañas archivadas se siguen devolviendo en /orders/getAll.
custom_max_per_hourstringTu techo de entrega para esta campaña, como cadena.
max_votes_per_dayintegerTope diario de votos, o null si no hay tope.
is_subscriptioninteger1 significa suscripción. Las suscripciones no se pueden editar tras la compra.
paused_unpauseddatetimeCuándo se pausó, reanudó o redimensionó la campaña por última vez. Es lo que inicia la espera de 30 segundos entre ediciones.

Los campos que no aparecen aquí alimentan la propia interfaz del panel. Léelos si quieres, pero no forman parte del contrato de integración y pueden cambiar sin aviso.

¿Está corriendo? ¿Ha terminado?

Una campaña no tiene campo de estado, así que lo deduces de cuatro columnas. Evalúa estas condiciones en orden y quédate con la primera que se cumpla.

ComprobaciónSignifica
1done === 1Cancelada. Se reembolsó el resto no gastado, ambas cantidades se pusieron a cero y se marcó como archivada.
2running === 0La pausaste tú. Reanúdala con /orders/unpause.
3remaining_accepted === 0Se ha entregado todo lo comprado.
4running === 1Funcionando con normalidad.
5archive === 1Oculta en el panel, pero se sigue devolviendo en /orders/getAll. Fíltrala si quieres que tu lista coincida con la del panel.

El orden importa. Cancelar fija done y archive a la vez, así que comprobar archive primero presentaría una campaña cancelada como simplemente archivada, y comprobar el restante antes que running presentaría una campaña en pausa como si estuviera entregando.

Progreso y reembolsos

amount_to_do cuenta votos aceptados; amount_done cuenta envíos. Solo se acepta accept_rate por ciento de los envíos, así que están en unidades distintas y restar uno del otro directamente es un error.

Este es el error de integración más común, y falla en silencio: los números siguen pareciendo razonables y la barra de progreso simplemente está mal. Con una tasa de aceptación del 70 por ciento, una campaña terminada se lee como un 70 por ciento; con el 50 por ciento, una campaña entregada a medias se lee como si no hubiera empezado. Convierte los envíos a votos aceptados primero, siempre.

JavaScript
// accept_rate arrives as a STRING, and it is per-site, not global.
const rate = Number(order.website.accept_rate)

// amount_done counts SUBMISSIONS; amount_to_do counts ACCEPTED votes.
// Convert before comparing them.
const delivered = order.amount_done * rate / 100
const remaining = Math.max(order.amount_to_do - delivered, 0)
const percent   = 100 * delivered / order.amount_to_do

// What cancelling right now would put back on your balance:
const refund    = (remaining / 1000) * order.website.price_per_1000

La misma cuenta pone precio a una cancelación: el reembolso es el resto no gastado al precio de lista del sitio, así que puedes saber cuánto vale parar una campaña antes de decidirte.

Una campaña de principio a fin

Seis llamadas, una clave API, sin navegador y sin inicio de sesión. Lo mismo con el endpoint SMM son tres llamadas — services, add, status — y no toca la API de plataforma.

bash
KEY=YOUR_API_KEY
BASE=https://backend.toplistbot.com

# 1. What can I order, and what does it cost?
curl -s "$BASE/orders/getAllWebsites" \
  | jq '.[] | {id, name, price_per_1000, max_per_hour}'

# 2. What can I afford?
curl -s -X POST "$BASE/api/v2" -d "key=$KEY" -d "action=balance"

# 3. Launch it.  cost = price_per_1000 * amount / 1000
curl -s -X POST "$BASE/orders/checkout?key=$KEY" \
  -H "Content-Type: application/json" \
  -d '[{"id":9,"amount":1000,
        "ownName":"https://arena-top100.com/index.php?a=in&u=me",
        "custom_max_per_hour":60}]'

# 4. Find the campaign that was just created.
curl -s "$BASE/orders/getAll?key=$KEY" | jq '.[0] | {id, url, amount_to_do, amount_done}'

# 5. Watch it. Poll every few minutes.
curl -s "$BASE/orders/graph/184223?key=$KEY"

# 6. Slow it down, or stop it.
curl -s -X PATCH "$BASE/orders/updateLimit?key=$KEY" \
  -H "Content-Type: application/json" -d '{"id":184223,"max_votes_per_day":200,"type":"set"}'
curl -s -X POST "$BASE/orders/pause?key=$KEY" \
  -H "Content-Type: application/json" -d '{"id":184223}'

Errores

Los errores llegan con su código HTTP correspondiente. Los fallos de validación devuelven un objeto `errors` indexado por nombre de campo.

  • 400La petición no se pudo leer: JSON mal formado, o una acción que el endpoint SMM no conoce.
  • 401Credencial ausente, caducada o incorrecta.
  • 402Saldo insuficiente. No se cobró nada.
  • 403Autenticado, pero sin permiso para hacer esto.
  • 404No existe ese registro, incluido uno que pertenece a otra persona.
  • 409Entra en conflicto con el estado actual de la cuenta, como activar el doble factor dos veces.
  • 422La validación falló. El cuerpo nombra cada campo.
  • 429Límite de frecuencia. El mensaje indica cuánto esperar.
  • 500Culpa nuestra. No se cobró nada.
  • 503Una dependencia no está disponible. Reintenta más tarde.
Validation error
{
  "errors": {
    "quantity": ["The quantity must be at least 1."]
  }
}

Cuando el cuerpo de la petición era un array, las claves de error llevan el índice de la línea que falló.

Unos pocos endpoints responden en texto plano y no en JSON: /orders/checkout, /orders/pause y /orders/updateLimit entre ellos. Decide según el código de estado, no según la forma del cuerpo.

Límites de frecuencia

Un 429 siempre indica cuánto esperar. Respétalo en lugar de reintentar a ciegas.

  • El mismo carrito se acepta como mucho una vez cada 60 segundos.
  • El total de votos de una campaña se puede cambiar una vez cada 30 segundos.
  • Los intentos de inicio de sesión se limitan por dirección y por IP.
  • Restablecer contraseña: 3 por dirección y 10 por IP cada 15 minutos.
  • `status` y `cancel` aceptan como máximo 100 ids de pedido por llamada.
  • Consulta el progreso cada minutos, no cada segundos. La entrega se mide en votos por hora.

Límites y notas

  • La cantidad del pedido debe estar entre 1 y 50000 acciones.
  • El intervalo es 15 por hora por defecto y tiene un tope de 4000. Pedir más que el máximo del propio sitio se rechaza con un 400 que indica el límite.
  • Las acciones `refill` y `refill_status` no están implementadas: crea un pedido nuevo en su lugar.
  • El campo `status` siempre vale literalmente "Completed" y no es una señal de progreso. Usa `remains == 0` para saber que un pedido ha terminado, y `start_count` para lo entregado.
  • Las suscripciones no se pueden editar tras la compra: pausa o cancela.
  • Los sitios de listados fijan sus propias reglas y las cambian con el tiempo. Eres responsable de asegurarte de que tu uso cumple los términos de cualquier sitio en el que promociones. No prometemos ninguna posición ni clasificación concreta.
Comienza gratis

Empieza a promocionar ¡ahora!

Verifica tu correo electrónico y recibe 100 tokens gratis para probar nuestro servicio. Sin compromiso.

Sin tarjeta de crédito
Cancela cuando quieras
Soporte 24/7