Referencia de la API: transferencias y cheques
Estos métodos permiten enviar pagos. Una transferencia envía fondos del saldo
de tu app a la billetera de un usuario de Telegram o los retiene hasta que un
nuevo destinatario abra el bot. Un cheque es un enlace canjeable que financias
por adelantado. Las convenciones (autenticación, formato de las respuestas,
montos, spend_id) están en la página de
referencia de la API para comerciantes.
Los tres métodos de pago se rigen por el
modo de pagos de la app: una app
nueva le paga a cualquiera desde el principio; si el dueño lo restringió,
solo se les puede pagar a los destinatarios de la lista
(403 recipient_not_allowed) o a nadie (403 payouts_disabled). El modo lo
fija el dueño en la Mini App; no se puede cambiar por API. Los usos permitidos
de estos pagos se establecen en las condiciones de la API para comerciantes.
transfer
POST /pay/api/transfer — ámbito payouts, límite de 30 por minuto.
Si el destinatario ya usa la app, recibe el pago al instante. Si el username
es desconocido, se crea una transferencia con estado pending: los fondos
quedan retenidos en escrow hasta que el destinatario abra el bot con ese nombre
de usuario. Los fondos sin reclamar se devuelven al saldo de la app después
del vencimiento a los 30 días (expires_at). Comprueba que el estado sea
status: "returned" antes de contabilizar la devolución.
Envía tú el invite_url: el bot no puede escribirle a alguien que nunca lo
inició. El estado final es completed o returned. Para seguirlo, suscríbete
a los webhooks opcionales transfer_completed y
transfer_returned, o consulta getTransfers.
| Parámetro | Tipo | Obligatorio | Significado |
|---|---|---|---|
user_id | integer | exactamente uno de user_id / username | id de Telegram del destinatario; esa persona debe haber abierto TgPay Crypto al menos una vez |
username | string | exactamente uno de user_id / username | nombre de usuario del destinatario, con o sin @; un nombre desconocido crea un pago pendiente |
asset | string | sí | código del activo |
amount | string | sí | string decimal positivo; también se aplica el máximo por transferencia de la plataforma y, si se establece, un mínimo (estimación del equivalente en dólares estadounidenses al tipo de cambio actual) |
spend_id | string | sí | clave de idempotencia, de 1 a 64 caracteres, única por pago |
comment | string | no | hasta 1024 caracteres, se muestra al destinatario |
disable_send_notification | boolean | no | true = no notificar al destinatario por Telegram en un pago inmediato; al recibir un pago que estaba pendiente, el destinatario siempre recibe una notificación |
El resultado es el objeto de transferencia: transfer_id, hash,
user_id, recipient_username, asset, amount, amount_minor, spend_id,
comment, status (pending / completed / returned), created_at,
completed_at, expires_at, invite_url. user_id puede ser null mientras
se espera al nuevo destinatario; completed_at es null hasta que se completa
la transferencia.
Errores: 403 payouts_disabled / 403 recipient_not_allowed (el
modo de pagos), 404 user_not_found
(el id es desconocido o el destinatario no está disponible),
400 invalid_recipient (el nombre de usuario del destinatario tiene un formato inválido),
400 amount_too_small / 400 amount_too_big
(fuera de los límites por transferencia), 409 insufficient_funds,
400 unknown_asset, 400 invalid_amount, y el par de spend_id
409 idempotency_conflict / 409 idempotency_in_progress. Demasiados
destinatarios desconocidos en un minuto hacen que las solicitudes para cualquier
destinatario devuelvan 429 rate_limited (consulta los
límites de frecuencia).
transferBatch
POST /pay/api/transferBatch — ámbito payouts, límite de 10 por minuto.
Una extensión para pagos masivos: hasta 100 transferencias en una llamada.
Un parámetro: items, un array JSON (envía la petición con cuerpo JSON; en
form-urlencoded o en la cadena de consulta devuelve 400 invalid_request) donde cada elemento contiene todos los
parámetros de transfer (user_id o username, asset, amount, spend_id, y los
opcionales comment y disable_send_notification). Los spend_id tienen que
ser únicos dentro del lote, o toda la llamada falla con
400 duplicate_spend_id antes de ejecutar nada. Una estructura inválida, el
modo de pagos de la app o su límite diario también pueden causar el rechazo
de toda la solicitud antes de enviar ningún pago. Si se acepta, los resultados
se devuelven en result.items.
Los elementos se procesan de forma independiente y en orden: un elemento
fallido nunca revierte a los demás. La llamada devuelve HTTP 200 con ok: true
incluso cuando algunos elementos fallaron, así que revisa siempre cada uno:
- éxito:
{"ok": true, "spend_id": "…", "result": <transfer object>} - fallo:
{"ok": false, "spend_id": "…", "error": {"code": …, "name": "…"}}con los mismos nombres de error que untransferindividual.
Los elementos del lote comparten el espacio de idempotencia con las
transferencias individuales: reintentar el lote entero —o reenviar un elemento
como un transfer individual con el mismo spend_id— devuelve el resultado
anterior sin pagar dos veces.
getTransfers
GET /pay/api/getTransfers — ámbito read. Filtros: asset,
transfer_ids (separados por comas), spend_id (coincidencia exacta: busca un
pago por tu propia clave), status (pending / completed / returned),
más offset / count. Devuelve
{"items": [transfer, …]}, los más recientes primero.
createCheck
POST /pay/api/createCheck — ámbito checks, límite de 60 por minuto.
Por defecto, crea un cheque de un solo uso con el saldo de tu app. Puede
canjearlo cualquiera que tenga el enlace o solo el usuario designado. La
extensión recipients permite crear una lista de destinatarios con un monto
individual para cada uno. El total se retiene al crear el cheque (pasa de
available a onhold en getBalance). La creación de cheques está sujeta a
los mismos límites de monto y de pagos diarios que las transferencias.
| Parámetro | Tipo | Obligatorio | Significado |
|---|---|---|---|
asset | string | sí | código del activo |
amount | string | salvo que se use recipients | cadena decimal positiva; con recipients, el total se calcula a partir de la lista |
pin_to_user_id | integer | no | solo este ID de Telegram puede canjearlo |
pin_to_username | string | no | solo este @usuario puede canjearlo (la @ es opcional; se ignora cuando también se usa pin_to_user_id). El nombre de usuario debe pertenecer a un usuario existente de la app |
spend_id | string | no | clave de idempotencia (extensión); usa una |
recipients | array | no | extensión: de 1 a 100 elementos, cada uno con user_id o username y un amount como cadena decimal positiva. No se puede combinar con un usuario designado |
password | string | no | extensión: contraseña necesaria para canjearlo; hasta 64 caracteres |
expires_in | integer | no | extensión: duración en segundos; omitido o 0 = sin vencimiento |
El resultado es el objeto de cheque: check_id, hash, asset,
amount, amount_minor, bot_check_url (el enlace de canje de t.me),
status (active / activated / expired — expired es una extensión),
pin_to_user_id, created_at,
activated_at, expires_at y recipients (null en un cheque normal; en caso
contrario, cada elemento contiene user_id, username, amount,
amount_minor y claimed_at). Cada canje genera el webhook
opcional check_activated; si es un cheque con lista de destinatarios,
incluye también activated_slot. Al expirar se devuelve el monto sin
canjear; si tiene una lista de destinatarios, puede enviarse check_expired.
active significa que el cheque todavía se puede canjear; un cheque cuyo
plazo terminó indica expired, y su monto sin canjear ya volvió al saldo de
tu app. Un cheque sin expires_in no expira nunca.
Errores: 403 payouts_disabled / 403 recipient_not_allowed (el
modo de pagos: en el modo allowlist,
todos los destinatarios, tanto el usuario designado como los de una lista,
deben estar autorizados), 400 unknown_asset, 400 invalid_amount,
404 user_not_found (el nombre de usuario designado no corresponde a nadie),
409 insufficient_funds y el par de spend_id.
Otros errores: 400 amount_too_small / 400 amount_too_big (fuera de los límites por transferencia). Para recipients (un array JSON en un cuerpo JSON): 400 invalid_slots (más de 100 elementos; una lista vacía devuelve 400 invalid_request), 400 invalid_recipient (elemento sin user_id / username válido), 400 duplicate_recipient (destinatario repetido), 400 self_claim (propietario de la app en la lista) y 400 invalid_pinned_user (recipients combinado con un usuario designado).
deleteCheck
POST /pay/api/deleteCheck — ámbito checks. Un parámetro: check_id.
Cancela un cheque activo y devuelve la parte sin canjear al saldo de tu app;
devuelve true. Errores: 404 check_not_found,
409 check_not_active (canjeado por completo, expirado o eliminado).
getChecks
GET /pay/api/getChecks — ámbito read. Filtros: asset, check_ids
(separados por comas), status (active / activated / expired), más offset /
count. Devuelve {"items": [check, …]}, los más recientes primero; los
cheques eliminados nunca se devuelven.
¿Te sirvió este artículo?
Gracias por tu comentario.