Facturas

Creá, listá, consultá y anulá facturas; todos los campos; cotizaciones; y cómo el hosted checkout maneja la elección de red, el estado en vivo y la vuelta a tu sitio.

Última actualización 27 oct 2026

Una factura le pide a un comprador un monto en USD, pagado en USDT o USDC en una red. Cada factura tiene su propia dirección de depósito, así que un pago se asocia a su factura por la dirección a la que se mandó.

Crear una factura

POST /api/v1/crypto/invoices — permiso crypto-invoices:create, header Idempotency-Key obligatorio (ver Idempotencia).

Hay dos formas de crearla:

  • Red y token fijos. Mandá network y token. La factura queda PENDING de inmediato y la respuesta trae deposit_address, total y payment_uri.
  • Elige el comprador. Omití los dos. La factura toma el entorno de tu API key; con una key legacy, mandá mode para elegirlo: Sandbox (mode: "test" en la API) o Live ("live"). La factura queda AWAITING_SELECTION; el comprador elige una red y un token en el hosted checkout, que recién ahí asigna la dirección.

Los requests válidos más chicos:

{ "amount": "49.00", "title": "Pro plan, 1 month", "network": "POLYGON_AMOY", "token": "USDC" }
{ "amount": "49.00", "title": "Pro plan, 1 month", "mode": "test" }

Un request completo, con un vendedor, la parte de un socio y un markup:

curl -X POST https://api.aliquot.cc/api/v1/crypto/invoices \
  -H "Authorization: Bearer $ALIQUOT_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-77310" \
  -d '{
    "amount": "100.00",
    "network": "POLYGON_AMOY",
    "token": "USDC",
    "fee_payer": "CUSTOMER",
    "markup_percent": 2,
    "merchant": "halden_type",
    "splits": [{ "account": "kerning_weekly", "percent": 10 }],
    "title": "Halden Grotesk — Desktop license",
    "merchant_order_id": "order-77310",
    "buyer_email": "[email protected]",
    "redirect_url": "https://shop.example.com/orders/77310",
    "metadata": { "cart_id": "c_5521" }
  }'

Campos del request

CampoTipoObligatorioDescripción
amountstringSíPrecio en USD, con como máximo dos decimales. Mínimo "1.00".
titlestringSíLo que se está pagando, 1–200 caracteres. Se muestra en el checkout.
currencystringNoSolo "USD", el valor por defecto.
networkstringCon tokenUno de POLYGON_MAINNET, POLYGON_AMOY, BSC_MAINNET, BSC_TESTNET, BASE_MAINNET, BASE_SEPOLIA. Mandalo junto con token, u omití los dos.
tokenstringCon networkUSDT o USDC, disponible en esa red (ver Redes y tokens).
modestringCon una key legacy, si no hay network"test" (Sandbox) o "live". Si también mandás network, tienen que coincidir. Una key de Sandbox o de Live completa su propio modo y responde 403 API_KEY_ENVIRONMENT_MISMATCH para el otro.
fee_payerstringNoCUSTOMER (por defecto): el comprador paga la comisión de procesamiento y el markup encima de amount. MERCHANT: el comprador paga amount y ambos salen de la parte del vendedor.
markup_percentnumberNoLa parte de tu plataforma, 0–20, con como máximo dos decimales. Por defecto 0.
merchantstringNoReference de la cuenta MERCHANT que vende. Si se omite, tu cuenta platform es el vendedor. Una cuenta PARTNER no puede ser el vendedor.
splitsarrayNoHasta 20 entradas { "account": "<reference>", "percent": <number> }. Cada porcentaje es mayor que 0 con como máximo dos decimales; en total, como máximo 100. Ninguna cuenta dos veces.
descriptionstringNoHasta 2000 caracteres.
merchant_order_idstringNoEl ID de tu pedido, 1–200 caracteres. Se puede buscar con q y viene en los webhooks invoice.created y refund.claimable.
redirect_urlstringNoA dónde manda el checkout al comprador después de pagar. Ver Volver a tu sitio.
metadataobjectNoCualquier objeto JSON. Se guarda y se devuelve tal cual.
buyer_emailstringNoSi está, el comprador recibe por email los links de reclamo de reembolsos. Nunca se muestra en el checkout.
expires_in_minutesintegerNoVentana de pago, 1–1440. Por defecto 30. Se cuenta desde la creación si mandás network y token; si no, desde que el comprador elige un par. Ver Ventana de pago.

Cómo fee_payer, markup_percent y splits se convierten en montos se explica, con un ejemplo resuelto, en Ledger y splits. Las cuentas nombradas en merchant y splits tienen que existir; una reference desconocida da 422 en ese campo.

El objeto factura

201 Created devuelve la factura. Un replay del mismo Idempotency-Key la devuelve con 200.

CampoDescripción
idinv_….
statusVer Estados.
livemodefalse en Sandbox, true en Live.
currency"USD".
fee_payerCUSTOMER o MERCHANT.
network, token, decimalsEl par de pago y los decimales del token. null mientras está AWAITING_SELECTION.
baseEl precio en unidades del token una vez elegido el par; antes, el precio en USD.
platform_fee, markup, merchant_net, totalEl desglose de comisiones en unidades del token. total es lo que el comprador tiene que mandar. null mientras está AWAITING_SELECTION.
receivedSuma de las transferencias en el token de la factura vistas hasta ahora.
deposit_addressLa dirección a la que paga el comprador. null mientras está AWAITING_SELECTION.
payment_uriUna URI EIP-681 para wallets y códigos QR, que pide exactamente total del token.
required_confirmationsEl umbral de confirmaciones que aplica a esta factura. Ver Confirmaciones.
expires_atFin de la ventana de pago.
merchant{ "reference", "name" } del vendedor.
splits[{ "account", "name", "percent", "amount" }]; amount es null hasta que se elige un par.
title, description, merchant_order_id, redirect_url, metadata, buyer_emailTal como se mandaron.
payment_link_idEl payment link que creó la factura (plink_…), o null si la creaste con este endpoint.
pay_urlEl hosted checkout: https://aliquot.cc/pay/{id}.
created_at, detected_at, paid_at, cancelled_atTimestamps; null hasta que ocurren.

Estados

EstadoSignificadoWebhook al entrar
AWAITING_SELECTIONEspera que el comprador elija una red y un token.invoice.created (al crearse)
PENDINGDirección asignada, esperando una transferencia.invoice.created (al crearse)
DETECTEDSe vio una transferencia y se está confirmando. No vence.invoice.detected
PAIDConfirmada, y el monto cubre el total.invoice.paid
OVERPAIDConfirmada con más que el total; el excedente es reembolsable.invoice.paid e invoice.overpaid
UNDERPAIDConfirmada pero incompleta. El comprador puede mandar el resto antes de expires_at.invoice.underpaid
EXPIREDLa ventana terminó sin que llegara nada.invoice.expired
EXPIRED_UNDERPAIDLa ventana terminó con un pago parcial, retenido para el comprador como reembolso.invoice.expired (y refund.claimable)
REFUNDEDEl pago parcial se le devolvió al comprador.refund.completed
CANCELLEDLa anulaste.Ninguno

El diagrama completo del ciclo de vida está en la Introducción.

Consultar una factura

GET /api/v1/crypto/invoices/{id} — permiso crypto-invoices:read.

Devuelve el objeto factura y además:

CampoDescripción
idempotency_keyEl Idempotency-Key con el que se creó (null para las facturas iniciadas desde un payment link).
transfers[{ "tx_hash", "token", "amount", "confirmations", "required", "status", "block_number" }]. status es SEEN (confirmándose), CONFIRMED u ORPHANED (su bloque fue reemplazado por una reorg). token difiere del de la factura en un pago con el token equivocado.
ledgerUna vez PAID u OVERPAID: el asiento de liquidación, { "id", "entries": [{ "side", "account", "amount" }] }. Ver Ledger y splits.
refundsLos reembolsos retenidos para el comprador de esta factura, con claim_url mientras se pueden reclamar. Ver Reembolsos.

Listar facturas

GET /api/v1/crypto/invoices — permiso crypto-invoices:read.

Parámetro de queryDescripción
modetest o live. Por defecto, el entorno de tu key (live con una key legacy).
statusUn estado de la tabla de arriba.
qBusca por ID de factura, dirección de depósito, hash de transacción o merchant_order_id.
cursor, limitPaginación; limit 1–100, por defecto 25.
curl "https://api.aliquot.cc/api/v1/crypto/invoices?mode=test&q=order-77310" \
  -H "Authorization: Bearer $ALIQUOT_API_KEY"

La respuesta es { "items": [...], "next_cursor": "..." }, de la más nueva a la más vieja.

Anular una factura

POST /api/v1/crypto/invoices/{id}/void — permiso crypto-invoices:update. Sin body.

Anular pasa una factura AWAITING_SELECTION o PENDING a CANCELLED y la devuelve. Cualquier otro estado responde 409 CONFLICT: una vez detectado un pago, la factura ya no se puede anular. Anular no manda ningún webhook.

Si el comprador paga igual una factura cancelada, el dinero no se le acredita al vendedor; queda retenido para el comprador como un reembolso LATE_PAYMENT.

Cotización

POST /api/v1/crypto/quote — permiso crypto-invoices:read. Calcula el mismo desglose que tendría una factura, sin crear nada.

{
  "amount": "100.00",
  "network": "POLYGON_AMOY",
  "token": "USDC",
  "fee_payer": "CUSTOMER",
  "markup_percent": 2,
  "merchant": "halden_type",
  "splits": [{ "account": "kerning_weekly", "percent": 10 }]
}

network y token son obligatorios; fee_payer, markup_percent, merchant y splits son opcionales y toman los mismos valores por defecto que en una factura. La respuesta:

{
  "network": "POLYGON_AMOY",
  "token": "USDC",
  "decimals": 6,
  "fee_payer": "CUSTOMER",
  "base": "100.00",
  "platform_fee": "0.50",
  "markup": "2.00",
  "merchant_net": "90.00",
  "total": "102.50",
  "splits": [{ "account": "kerning_weekly", "percent": 10, "amount": "10.00" }]
}

El hosted checkout

Mandá al comprador a pay_url (https://aliquot.cc/pay/{id}). La página no necesita nada más de tu parte.

  • Elección de red. En una factura AWAITING_SELECTION, el comprador primero elige uno de los pares de red y token disponibles en el entorno de la factura. Al elegir, se asigna la dirección de depósito, se calcula total para ese token y la ventana de pago vuelve a arrancar: el comprador tiene todo el expires_in_minutes desde ese momento. Una vez elegido, el par no se puede cambiar.
  • Pago. El comprador ve el monto exacto, la dirección y un código QR (la payment_uri EIP-681), y puede pagar desde una wallet del navegador con un botón, que primero cambia la wallet a la red correcta.
  • Estado en vivo. La página sigue a la factura mientras pasa por DETECTED, con un contador de confirmaciones, hasta PAID, y después muestra un comprobante, con la entrega del payment link cuando la hay. Si el comprador paga de menos, la página le pide el resto; si la factura vence o hay un reembolso retenido, la página lo indica.

El checkout está construido sobre endpoints públicos que también podés llamar para armar tu propia página de pago:

EndpointDescripción
GET /api/v1/public/pay/{id}La vista de la factura apta para el comprador: montos, dirección, confirmations, allowed_pairs, estado del reembolso y fulfillment (null hasta que la factura está pagada; ver Payment links). Sin datos del ledger ni IDs internos.
POST /api/v1/public/pay/{id}/selectBody { "network", "token" }. Elige el par de una factura AWAITING_SELECTION. 409 si ya se eligió un par distinto o si la factura venció.
GET /api/v1/public/pay/{id}/streamServer-sent events. Un evento invoice trae la misma vista que GET /api/v1/public/pay/{id} en cada cambio. El stream se cierra cuando la factura llega a PAID, OVERPAID, EXPIRED, EXPIRED_UNDERPAID, REFUNDED o CANCELLED, y si no, a los 30 minutos; EventSource se reconecta solo.
const source = new EventSource('https://api.aliquot.cc/api/v1/public/pay/inv_01JB7Q8M3X4K9TPZ2R6WVN5HDC/stream');
source.addEventListener('invoice', (e) => {
  const view = JSON.parse(e.data);
  console.log(view.status, `${view.confirmations}/${view.required_confirmations}`);
});

Cualquiera que tenga el ID de la factura puede abrir su checkout, así que no trates el ID como un secreto, y nunca entregues un pedido a partir de lo que informa un navegador. Entregalo a partir del webhook invoice.paid o de GET /api/v1/crypto/invoices/{id}.

Volver a tu sitio

Cuando el checkout ve que la factura llega a PAID mientras el comprador la tiene abierta, cuenta cinco segundos y navega a redirect_url; el comprador puede elegir quedarse. Un comprador que abre la página después recibe, en cambio, un link para volver, y lo mismo pasa cuando el comprobante muestra la entrega de un payment link, para que no se la pierda. Aliquot no le agrega nada a la URL, así que poné lo que necesites para encontrar el pedido en la propia redirect_url, por ejemplo https://shop.example.com/orders/77310.

Llegar a redirect_url no prueba el pago. Verificá el estado de la factura en tu servidor.

Ventana de pago

expires_in_minutes (30 por defecto) es la ventana de pago: cuánto tiempo tiene el comprador para mandar la plata una vez que existe una dirección de depósito.

  • Red y token enviados al crear. La ventana arranca al crear la factura: expires_at es el momento de creación más expires_in_minutes.
  • El comprador elige la red. Primero expires_at limita la elección: el comprador tiene que elegir un par dentro de los expires_in_minutes desde la creación, o la factura pasa a EXPIRED. Al elegir, expires_at pasa a ser el momento de la elección más el mismo expires_in_minutes, así que el comprador siempre tiene la ventana completa para pagar, y todo el flujo puede durar hasta el doble de expires_in_minutes.

Las facturas creadas desde un payment link usan de la misma forma la ventana por defecto de la organización (30 minutos). Una factura que sigue PENDING o AWAITING_SELECTION en expires_at pasa a EXPIRED; una que está UNDERPAID pasa a EXPIRED_UNDERPAID. Una factura DETECTED nunca vence, porque el comprador pagó a tiempo.