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; debe ser un usuario existente de la app |
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í | cadena decimal positiva; sujeta también al mínimo y al máximo por transferencia de la plataforma, calculados en dólares a los tipos de cambio actuales |
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.
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 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), 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.
La respuesta actual indica status: "active" para todos los cheques que no
se hayan canjeado por completo, incluso si han expirado. Consulta también
expires_at: el estado active por sí solo no demuestra que el enlace
siga siendo canjeable.
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.
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), 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.