Referencia de la API para comerciantes
Las convenciones que comparten todos los métodos, más los métodos de catálogo de solo lectura. Consulta los detalles de cada método en estas páginas: facturas y reembolsos, transferencias y cheques, suscripciones, webhooks.
La API sigue las convenciones de Crypto Bot para los métodos aquí documentados. Cambia la URL base y el token, y prueba en la red de prueba los métodos que use tu integración. Nuestras funciones adicionales se indican como extensión.
También hay una especificación OpenAPI 3.1 legible por máquina: crypto-pay-openapi.yaml · crypto-pay-openapi.json. Pásasela a generadores de código, clientes de API o tus herramientas de IA, pero consulta también las páginas de cada método: las extensiones más recientes pueden tardar en incorporarse a la especificación.
URL base y autenticación
Todos los métodos están disponibles en
https://app.tgpaycrypto.com/pay/api/<methodName>. En la
red de prueba la base es
https://testnet.tgpaycrypto.com/pay/api: apps y tokens separados, fondos de prueba sin
valor real.
Autentica cada petición con el token en la cabecera
TgPayCrypto-API-Token (TgCryptoPay-API-Token, el nombre anterior al
2026-09-07, y Crypto-Pay-API-Token se aceptan como alias de compatibilidad;
si se envían varias, gana la canónica). Un token ausente,
inválido o revocado devuelve 401 unauthorized. Lo mismo ocurre con un token
restringido vencido, el token de una app eliminada o uno cuyo titular esté
bloqueado.
El token tiene la forma <app_id>:<secret> y se muestra una sola vez, al
crearlo o al renovarlo; el servidor guarda solo su hash. Mira
Empezar como desarrollador.
Tokens y ámbitos
Dos tipos de credenciales se autentican igual:
- El token principal: acceso completo a todos los métodos, y la única clave que firma los webhooks.
- Los tokens restringidos (extensión): hasta 10 sin revocar por app, incluidos los vencidos. Abre Más → API para comerciantes, elige la app y entra en Acceso y tokens. Créalos en Tokens restringidos, cada uno con una etiqueta y un subconjunto de ámbitos. Revocar uno es instantáneo y no toca a los demás; renovar el token principal tampoco los toca. Un token también puede tener una fecha de vencimiento; después de esa fecha deja de servir para autenticarse.
| Ámbito | Métodos que desbloquea |
|---|---|
| (cualquier token válido) | getMe, getCurrencies, getExchangeRates |
read | getBalance, getStats, getInvoices, getChecks, getTransfers, getSubscriptionPlans, getSubscriptions |
invoices | createInvoice, deleteInvoice |
refunds | refundInvoice |
payouts | transfer, transferBatch |
checks | createCheck, deleteCheck |
subscriptions | createSubscriptionPlan, archiveSubscriptionPlan, cancelSubscription |
webhooks | updateApp |
Los ámbitos son aditivos e independientes: invoices no implica read, así que
un servidor que solo crea facturas puede usar un token sin acceso a los saldos ni al historial de pagos.
Llamar a un método que el token no cubre devuelve 403 scope_required.
getMe informa los scopes del token actual (null para el token principal) y
su token_name, así que puedes comprobar qué token estás usando y qué permite hacer.
Modo de pagos
Un ámbito dice qué métodos puede llamar un token; el modo de pagos de la
app dice a quién puede pagar cualquiera de sus tokens, incluido el principal.
Una app nueva le paga a cualquiera desde el primer minuto; el dueño puede
restringirlo en Más → API para comerciantes: abre la app y entra en Configuración de pagos → Pagos a través de la API.
Esto limita lo que se puede hacer si un token se filtra, igual que el límite diario. Volver
a ampliarlo requiere su PIN o biometría; la API solo puede leerlo (getMe →
payout_mode).
payout_mode | Qué pueden hacer transfer, transferBatch y createCheck |
|---|---|
any | pagarle a cualquier usuario, dejar un pago en espera para un @username desconocido, crear cheques al portador: el valor por defecto y el comportamiento de Crypto Bot |
allowlist | pagar solo a los usuarios de Telegram de la lista. Todos los destinatarios de un cheque, tanto el usuario designado como los de una lista, deben estar autorizados. Otros destinatarios, los @username desconocidos y los cheques al portador devuelven 403 recipient_not_allowed |
off | nada: toda llamada de pago devuelve 403 payouts_disabled; las facturas, las suscripciones, los reembolsos y los webhooks funcionan como siempre |
Si se rechaza un pago, el dueño recibe un aviso en Telegram y puede cambiar el modo. El límite diario de pagos se aplica además del modo. Para qué pueden usarse los pagos lo establecen las condiciones de la API para comerciantes.
Peticiones y respuestas
- Los métodos de lectura son
GETcon parámetros en la cadena de consulta. Los métodos que mueven dinero son soloPOST: los parámetros van como cuerpo JSON, form-urlencoded o parámetros de consulta (ante conflicto gana el cuerpo);multipart/form-datase rechaza. - Las respuestas generadas por los métodos de la API usan esta estructura JSON:
éxito
{"ok": true, "result": …}, error{"ok": false, "error": {"code": <HTTP status>, "name": "<error_name>"}}. Usaerror.namepara decidir cómo gestionar el error: es un identificador estable. - Un parámetro de consulta con un tipo incorrecto en un método GET (por
ejemplo,
offset=abc) puede rechazarse antes de que se ejecute el método de la API. Comprueba el estado HTTP: no todas las respuestas de error tienen la estructura anterior. Envía los parámetros de consulta con los tipos esperados.
Montos
- Los montos en cripto son cadenas decimales en unidades del activo
(
"10.5"), nunca números JSON. Las respuestas también llevanamount_minor(extensión): el valor entero en unidades mínimas como cadena, porque los enteros a escala de wei pueden superar la precisión exacta de unNumberde JavaScript. - Los
decimalspor activo vienen degetCurrencies: usa ese valor para calcular los montos en vez de fijarlo en el código. - Los montos en fiat tienen como máximo 2 decimales.
- Los tipos de cambio son cadenas de punto fijo, nunca números.
Paginación
Los métodos de listado (getInvoices, getChecks, getTransfers,
getSubscriptions) toman offset (por defecto 0) y count (por defecto 100,
máx. 1000; getSubscriptions máx. 500) y devuelven {"items": […]}, los más
recientes primero. Los filtros por ID (invoice_ids, check_ids,
transfer_ids) son listas de enteros separadas por comas. Las marcas de tiempo
siempre son cadenas ISO 8601.
Idempotencia: spend_id
Los métodos que mueven dinero toman una clave spend_id generada por quien
llama (de 1 a 64 caracteres): obligatoria en transfer y en cada elemento de
transferBatch, opcional en createCheck y refundInvoice (extensión — úsala
igual). Reintentar con la misma clave y los mismos parámetros devuelve el
resultado original en vez de mover fondos dos veces, así que puedes reintentar una petición que
superó el tiempo de espera. La misma clave con parámetros
distintos devuelve 409 idempotency_conflict; un reintento mientras la
original sigue ejecutándose devuelve 409 idempotency_in_progress.
Límites de frecuencia
Se aplican por app y se comparten entre todos sus tokens. Al superarlos se
devuelve 429 rate_limited:
| Método | Límite |
|---|---|
createInvoice, createCheck | 60 por minuto |
refundInvoice | 30 por minuto |
transfer | 30 por minuto |
transferBatch | 10 por minuto |
updateApp | 10 por minuto |
createSubscriptionPlan | 20 por minuto |
Pueden aplicarse otros límites a las peticiones. Si recibes 429 rate_limited,
aumenta la espera antes de volver a intentarlo. Durante el mantenimiento de
la plataforma, los métodos de escritura devuelven 503 maintenance y las
lecturas siguen funcionando.
Métodos de catálogo y de cuenta
getMe
GET /pay/api/getMe — sin parámetros. Devuelve la identidad de la app:
app_id, name, payment_processing_bot_username, webhook_url,
webhook_events (los tipos de webhook extendidos que la app activó), los
campos de introspección del token scopes / token_name descritos arriba y
payout_mode (off / allowlist / any), daily_payout_max_usd_cents
(0 = sin límite establecido por el titular) y daily_payout_spent_usd_cents
(lo gastado durante las últimas 24 horas).
updateApp
POST /pay/api/updateApp — ámbito webhooks. Parámetros opcionales:
name (de 1 a 64 caracteres), webhook_url (una URL HTTPS pública; una cadena
vacía la elimina) y webhook_events (un array o una lista separada por comas
con los nombres de los eventos adicionales admitidos). Una lista de eventos
vacía deja únicamente invoice_paid. Devuelve los mismos campos de la app
que getMe.
getBalance
GET /pay/api/getBalance — sin parámetros. Devuelve un array con una fila por
activo admitido, incluso si el saldo es cero: currency_code, available (saldo
disponible), onhold (fondos de cheques sin canjear y pagos pendientes a @username) y
amount_minor.
getCurrencies
GET /pay/api/getCurrencies — sin parámetros. La lista de referencia de lo que
admite la API: filas de cripto (is_blockchain: true) y las monedas fiat en las
que se pueden cotizar las facturas (is_fiat: true). Cada fila lleva code,
name, decimals y la marca is_stablecoin.
getExchangeRates
GET /pay/api/getExchangeRates — sin parámetros. Cotizaciones de cripto a
fiat: source, target, rate (una cadena de punto fijo) e is_valid.
Estos tipos de cambio son orientativos. is_valid: true no garantiza que una
cotización esté actualizada. Si no se pueden obtener tipos de cambio, el
resultado puede ser un array vacío. Para comprobar un pago real, usa los
montos y los tipos de cambio registrados en la factura.
getStats
GET /pay/api/getStats — start_at / end_at opcionales (ISO 8601; la
ventana por defecto son las últimas 24 horas). Devuelve volume (valor en
dólares de las facturas pagadas durante ese período, estimado a los tipos de
cambio actuales; los activos sin precio se contabilizan como cero), conversion (pagadas/creadas,
en porcentaje), unique_users_count, created_invoice_count,
paid_invoice_count y los límites efectivos de la ventana. Una fecha que no se
puede interpretar devuelve 400 invalid_date.
Errores que puede devolver cualquier método
| HTTP | error.name | Cuándo |
|---|---|---|
| 401 | unauthorized | token ausente, inválido o revocado |
| 403 | scope_required | el token no tiene el ámbito del método |
| 403 | payouts_disabled | el modo de pagos de la app es off (solo en los métodos que envían pagos) |
| 403 | recipient_not_allowed | el destinatario no está en la lista de destinatarios de la app (solo en los métodos que envían pagos) |
| 400 | invalid_request | parámetros inválidos o que no se pueden interpretar (POST) |
| 403 | daily_cap_exceeded | se superaría el límite diario de pagos de la app |
| 403 | verification_required | las operaciones salientes del titular están restringidas; afecta a transferencias, cheques y reembolsos |
| 503 | merchant_payouts_paused | los cargos al saldo de la app están temporalmente suspendidos |
| 429 | rate_limited | se superó el límite de frecuencia |
| 503 | maintenance | mantenimiento de la plataforma (métodos de escritura) |
| 500 | internal_error | error inesperado del servidor |
Los errores propios de cada método están listados en la página de ese método.
Errores sin el formato JSON
Una respuesta de error en texto sin formato o HTML no permite identificar por sí sola en qué capa se produjo. Revisa el estado HTTP, el cuerpo y los encabezados de la respuesta.
Si Cloudflare devuelve error code: 1010, ha rechazado al cliente por la firma del navegador antes de que la solicitud llegara a la API. Los permisos del token no son la causa de este error de Cloudflare. Un User-Agent ausente o no estándar puede activar la protección de red. Prueba a enviar un encabezado User-Agent que identifique a tu cliente, como MyShop/1.0, y repite la solicitud; esto no garantiza que se solucione. Si el error persiste, envía a soporte el estado HTTP, el cuerpo y los encabezados de la respuesta, tras eliminar los tokens y las cookies.
¿Te sirvió este artículo?
Gracias por tu comentario.