Referencia de la API: facturas y reembolsos
Los métodos de facturas: createInvoice, getInvoices, deleteInvoice,
refundInvoice. Las convenciones (autenticación, envoltorio, montos,
spend_id) están en la página de
referencia de la API para comerciantes; el recorrido
guiado es Aceptar pagos con facturas.
createInvoice
POST /pay/api/createInvoice — ámbito invoices, límite de 60 por minuto.
| Parámetro | Tipo | Obligatorio | Significado |
|---|---|---|---|
currency_type | string | no | crypto (por defecto) o fiat |
asset | string | modo cripto | el activo a cobrar, por ejemplo USDT. No se permite junto con fiat |
fiat | string | modo fiat | la moneda fiat en la que está el precio (las filas is_fiat de getCurrencies) |
accepted_assets | string / array | no | solo en modo fiat: los activos con los que puede pagar quien paga — una cadena separada por comas ("USDT,GRAM") o un array JSON. Si se omite = todos los activos admitidos |
amount | string | sí, salvo que se use open_amount | cadena decimal positiva: unidades del activo en modo cripto, unidades fiat (máx. 2 decimales) en modo fiat |
open_amount | boolean | no | extensión, solo en modo cripto: sin monto fijo — quien paga ingresa uno al pagar (donaciones y propinas). Excluyente con amount |
description | string | no | hasta 1024 caracteres, se le muestra a quien paga |
hidden_message | string | no | hasta 2048 caracteres, se le revela a quien paga solo después del pago |
payload | string | no | hasta 4096 caracteres de datos propios, devueltos en la factura y en el webhook |
allow_comments | boolean | no | permitir que quien paga adjunte un comentario (por defecto true) |
allow_anonymous | boolean | no | permitir que quien paga oculte su identidad (por defecto true) |
paid_btn_name | string | no | botón posterior al pago: viewItem, openChannel, openBot o callback |
paid_btn_url | string | no | la URL http(s) del botón — obligatoria cuando se usa paid_btn_name |
swap_to | string | no | intercambiar automáticamente los pagos recibidos a este activo. Se hace lo posible: si el intercambio no puede correr al momento del pago, el pago igual funciona sin intercambiar |
expires_in | integer | no | segundos hasta que la factura expira, hasta 2678400 (31 días); omitido o 0 = nunca |
rate_lock_seconds | integer | no | extensión, solo en modo fiat: congelar los tipos de conversión al crearla durante esta ventana (mira más abajo) |
El resultado —y el payload del webhook invoice_paid— es el objeto de
factura. Sus campos clave:
- Identidad y estado:
invoice_id,hash(el id público dentro depay_url),status(active/paid/expired),pay_url— el enlace det.meque le envías a quien paga (bot_invoice_url,mini_app_invoice_urlyweb_app_invoice_urlson alias de él). - Montos:
amount(el valor nominal — unidades fiat en una factura fiat, cripto en el resto;nullmientras una factura de monto abierto está sin pagar),amount_minor, y en las facturas fiat pagadaspaid_asset/paid_amount/paid_fiat_rate: la cripto realmente cobrada y el tipo usado. - Comisión:
fee_asset/fee_amount, sellados al pagar — la cifra de referencia para tus libros (feeyusd_rateson alias obsoletos de Crypto Bot). Mira comisiones y límites. - Quien paga:
paid_by_user_id(nullcuando eligió el anonimato),paid_anonymously,comment. - Reembolsos (extensión):
refunded_amount/refunded_minor(acumulados) yrefunded_at, sellado una vez reembolsada por completo. - Fijación del tipo (extensión):
rate_lock_untilyrate_lock_rates— los tipos sellados por activo,nullcuando no se pidió ninguna fijación. - Tal como se creó:
description,hidden_message,payload,paid_btn_name/paid_btn_url,expiration_date(expires_ates un alias), los campos de intercambio (swap_to,is_swapped,swapped_to,swapped_rate,swapped_output, …).
Errores: 400 invalid_currency (activo y fiat mezclados),
400 invalid_amount, 404 unknown_asset, 400 unsupported_fiat,
400 paid_btn_url_required, y para las peticiones con fijación de tipo
400 rate_lock_fiat_only, 409 ratelock_disabled, 409 rate_unavailable (no
hay un tipo fresco para un activo aceptado — reintenta).
Cómo se pagan las facturas
Quien paga lo hace con el saldo de su billetera en la Mini App, al instante
y sin comisión de red. También puede financiar la factura desde una billetera
externa: la app le muestra una dirección de depósito, su transferencia llega a
su propia billetera y la factura se liquida sola en cuanto aterriza. En
cualquier caso tú ves lo mismo: una factura paid normal y un webhook
invoice_paid; no hay parámetros ni campos extra que manejar.
En una factura fiat, el monto en cripto se calcula al momento del pago, redondeado a tu favor, así que nunca recibes menos que el valor nominal en fiat. Si no hay un tipo fresco disponible, el pago falla del lado de quien paga en vez de liquidarse a un tipo viejo.
Fijar el tipo en una factura fiat
Pasa rate_lock_seconds para sellar el tipo del momento de cada activo
aceptado al crearla. Mientras la fijación está viva, quien paga ve exactamente
los montos sellados y el pago se convierte al tipo sellado: tú asumes el riesgo
de tipo de cambio durante la ventana. El servidor acota la ventana entre 60
segundos y el máximo de la plataforma (hoy 15 minutos).
Cuando la fijación caduca, la factura sigue siendo pagable y vuelve en silencio
a la conversión del momento del pago. Si quieres que la factura muera con la
cotización, pon expires_in con el mismo valor.
getInvoices
GET /pay/api/getInvoices — ámbito read. Filtros: asset, fiat,
invoice_ids (separados por comas), status (active / paid /
expired — expired es una extensión; active excluye las facturas que ya
pasaron su fecha límite), más offset / count. Devuelve
{"items": [invoice, …]}, las más recientes primero.
deleteInvoice
POST /pay/api/deleteInvoice — ámbito invoices. Un parámetro:
invoice_id. Cancela una factura sin pagar y devuelve true. Errores:
404 invoice_not_found, 409 invoice_already_paid — una factura pagada no se
puede eliminar, el dinero ya se movió.
refundInvoice
POST /pay/api/refundInvoice — ámbito refunds, límite de 30 por minuto.
Una extensión sobre Crypto Bot: devuelve el monto nominal de una factura pagada
—o parte de él— desde el saldo de tu app a quien la pagó, incluidos quienes
pagaron de forma anónima, sin revelar quiénes eran.
| Parámetro | Tipo | Obligatorio | Significado |
|---|---|---|---|
invoice_id | integer | sí | la factura pagada |
amount | string | no | el monto a reembolsar, en el activo de la factura. Omitido = todo el resto sin reembolsar. Los reembolsos parciales se acumulan hasta el monto nominal |
spend_id | string | no | clave de idempotencia — usa una, para que un reintento por tiempo agotado repita en vez de reembolsar dos veces |
El resultado es el objeto de factura actualizado con los acumulados
refunded_amount / refunded_minor; refunded_at se sella una vez que la
factura está reembolsada por completo. El estado sigue siendo paid. La
comisión de la plataforma no se devuelve. Cada reembolso dispara el
webhook opcional refund_completed.
Errores: 404 invoice_not_found, 409 invoice_not_paid,
409 already_refunded (no queda nada por reembolsar), 409 amount_too_big
(más que el resto sin reembolsar), 409 insufficient_funds,
400 invalid_amount, y el par de spend_id 409 idempotency_conflict /
409 idempotency_in_progress.
¿Te sirvió este artículo?
Gracias por tu comentario.