Referencia de la API
Catálogo completo de todos los endpoints públicos de Liqfy v1. Todas las rutas son relativas a la URL base de producción — https://api.liqfy.com.br/v1. (Todavía no hay un host de sandbox dedicado).
Autentique cada solicitud con su clave de API en el encabezado Authorization: Bearer <key> — Authorization: Bearer <LIQFY_API_KEY> (lq_test_*/lq_live_*). El encabezado heredado apikey: <key> se sigue aceptando por compatibilidad. Todos los cuerpos son JSON. Todos los importes son enteros en la unidad monetaria más pequeña.
La API se organiza en torno a unos pocos recursos:
- Cobros (
/v1/charges) — crear y consultar cobros Pix:object: "charge", idsch_…, encabezadoIdempotency-Key, bloquepix. Aquí comienza toda integración. - Billeteras (
/v1/wallets) — el saldo de su cuenta. - Operaciones de pago (
/v1/payments) — cancelación, estadísticas, comprobantes y otras operaciones sobre un cobro, identificado por su id sin procesar (sin el prefijoch_). Los reembolsos se emiten desde el panel de administración, no desde esta API. - Webhooks (
/v1/webhooks) — registrar endpoints e inspeccionar entregas.
#Cobros
/v1/charges.
Contrato público de Convenciones de la API §3. Cada respuesta se construye mediante un serializador de lista de permitidos: aquí no puede aparecer ningún id interno, nombre de PSP, costo ni payload sin procesar del proveedor.
#Crear cobro
POST /v1/charges — atajo orientado a Pix: POST /v1/pix/charges fija payment_method: "pix" en el cuerpo (sobrescribiendo cualquier valor que envíe) y devuelve exactamente el mismo Charge.
Encabezados
| Encabezado | Obligatorio | Notas |
|---|---|---|
Authorization | sí | Bearer + su clave de API (lq_test_* / lq_live_*). El encabezado heredado apikey se sigue aceptando. |
Idempotency-Key | sí | Cualquier cadena no vacía, con ámbito por (merchant, key). Es una escritura financiera: omitirlo produce un 400. |
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
amount | entero | sí | Unidad monetaria más pequeña, > 0. |
currency | cadena | no | Código ISO 4217 de 3 letras, convertido a mayúsculas por la API. Valor predeterminado: "BRL". Los cobros Pix deben usar BRL. |
payment_method | cadena | sí | "pix" — el único valor aceptado hoy. |
description | cadena | no | Hasta 500 caracteres; se incorpora a metadata.description en la lectura. |
expires_in | entero | no | Validez del Pix en segundos, 60–604800 (7 días). Fuera de ese rango la API responde 400: el valor nunca se recorta. Cuando el proveedor devuelve su propio pix.expires_at, ese valor prevalece. |
customer.name | cadena | no | |
customer.document | cadena | no | CPF o CNPJ. |
customer.email | cadena | no | Debe ser una dirección de correo electrónico válida. |
customer.phone | cadena | no | |
expected_payer_tax_id | cadena | no | Vincula el cobro a un pagador: dígitos de CPF (11) o CNPJ (14) con dígito verificador válido (normalizados a solo dígitos). Si también envía customer.document, ambos deben coincidir; si lo define, customer.name pasa a ser obligatorio. |
metadata | objeto | no | Formato libre; se eliminan las claves reservadas o con prefijo de guion bajo. |
Ejemplo
curl -X POST https://api.liqfy.com.br/v1/pix/charges \
-H "Authorization: Bearer $LIQFY_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"amount": 1000,
"currency": "BRL",
"description": "Pedido #12345",
"customer": { "name": "Maria Silva", "document": "12345678901" }
}'Respuesta 201 Created
{
"id": "ch_a1b2c3d4-0000-0000-0000-000000000009",
"object": "charge",
"amount": 1000,
"currency": "BRL",
"status": "pending",
"payment_method": "pix",
"customer": { "name": "Maria Silva", "document": "12345678901" },
"pix": {
"br_code": "000201BRCODEPIX",
"qr_code_url": "https://qr.example/img.png",
"expires_at": "2026-07-23T15:00:00.000Z"
},
"checkout_url": "https://checkout.liqfy.com.br/a1b2c3d4-0000-0000-0000-000000000009",
"settlement": {},
"metadata": { "order_id": "12345" },
"created_at": "2026-07-23T14:30:00.000Z"
}pix.txid (cuando el proveedor vinculó uno) y settlement.end_to_end_id (solo una vez paid y liquidado) son datos Pix contextuales — consulte PIX. charge.id nunca es igual a charge.pix.txid.
Reenviar la misma Idempotency-Key con el mismo cuerpo devuelve el 201 original y establece el encabezado de respuesta Idempotency-Replayed: true.
checkout_url es el checkout alojado de Liqfy para el cobro: redirija al pagador allí en lugar de renderizar su propia pantalla Pix. Se devuelve tanto en la creación como en GET /v1/charges/{id}, y no se puede derivar de charge.id (la ruta del checkout omite el prefijo ch_).
Vocabulario público de estados: pending, processing, paid, failed, expired, cancelled, refunded, disputed.
#Obtener cobro
GET /v1/charges/{id}
Acepta el id con prefijo ch_… o el id interno sin procesar. Con ámbito en la cuenta del llamante: un cobro de otra cuenta devuelve 404.
Respuesta 200 OK — la misma forma Charge que en la creación.
Cuando se abre un caso MED sobre el cobro, metadata.med.caseId contiene el id público de ese caso MED (med_…, el mismo id que GET /v1/med/cases/{id}), para que pueda vincular el cobro con el caso. El id de caso propio del proveedor nunca se expone.
#Obtener cobro por clave de idempotencia
GET /v1/charges/by-idempotency-key/{key}
Busca el cobro que creó con una Idempotency-Key determinada: útil para recuperar un cobro tras un timeout sin repetir la creación. Con ámbito en la cuenta del llamante. Se recortan los espacios de la clave; una clave vacía o de más de 255 caracteres responde 400.
Respuesta 200 OK — la misma forma Charge que en la creación.
#Listar cobros
GET /v1/charges
GET /v1/charges lista los cobros de la cuenta con paginación por cursor ({ object: "list", data, has_more, next_cursor }): el orden es createdAt desc, estable, sin page/offset en esta ruta.
GET /v1/charges?limit=25&starting_after=ch_01J…&status=paid| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
limit | entero | 25 | 1–100. |
starting_after | cadena | — | Un id de cobro (ch_…) del mismo recurso: cursor, no un offset. Hasta 140 caracteres. |
status | enum | — | Vocabulario público de estados (pending, paid, …). |
created_after | ISO 8601 | — | Límite inferior inclusivo sobre created_at. |
created_before | ISO 8601 | — | Límite superior inclusivo sobre created_at. |
customer_id | cadena | — | Filtra por documento del pagador. Hasta 140 caracteres. |
idempotency_key | cadena | — | Filtra por la Idempotency-Key usada en la creación (1–255 caracteres, recortados). |
{
"object": "list",
"data": [],
"has_more": false,
"next_cursor": null
}page/offset nunca se aceptan en esta lista por cursor — solo starting_after. Cuando has_more es true, pase next_cursor como starting_after para obtener la siguiente página.
Para una vista paginada y filtrable de las mismas transacciones, consulte GET /v1/payments.
#Billeteras
/v1/wallets. Los saldos de su cuenta. Solo lectura, con ámbito en su clave de API: las rutas de escritura bajo /v1/wallets/* son exclusivas del panel y responden 403 a una clave de API.
#Obtener saldo
GET /v1/wallets/balance
El parámetro de consulta currency es opcional. Sin él (la forma recomendada) la respuesta incluye todas las monedas de la cuenta en balances[], además de los campos de la moneda principal (BRL por defecto) en el nivel superior:
curl "https://api.liqfy.com.br/v1/wallets/balance" \
-H "Authorization: Bearer $LIQFY_API_KEY"Respuesta 200 OK
{
"available": 880,
"pending": 0,
"total": 880,
"retained": 0,
"currency": "BRL",
"next_release_at": null,
"next_release_amount": null,
"balances": [
{ "currency": "BRL", "available": 880, "held": 0, "pending": 0, "total": 880 }
],
"primary": { "currency": "BRL", "available": 880, "held": 0, "pending": 0, "total": 880 }
}| Campo | Descripción |
|---|---|
available | Saldo disponible para gastar/retirar de la moneda principal, en la unidad más pequeña (centavos para BRL). 880 = R$ 8,80. Con signo: se vuelve negativo cuando la cuenta tiene deuda. |
held | Importe retenido (bloqueado en tránsito) en las entradas balances[]/primary. No está presente en el nivel superior. |
pending | Liquidado pero aún retenido: todavía no disponible (moneda principal). Incluye las retenciones por reembolso en curso, por lo que puede ser mayor que retained. |
total | available + held + pending de la moneda principal. |
retained | Total bajo retención (retenciones PENDING) de la moneda principal. No incluye las retenciones por reembolso. |
currency | Moneda principal (ISO 4217). Valor predeterminado: BRL. |
next_release_at | Cadena ISO 8601 del momento en que se libera el próximo tramo pending, o null cuando no hay nada programado. |
next_release_amount | Importe de esa próxima liberación (unidad monetaria más pequeña), o null. |
balances[] | Una entrada por moneda: { currency, available, held, pending, total }. |
primary | La moneda principal (mismos campos que una entrada de balances[]). |
Los campos de nivel superior (available/pending/total/currency) corresponden a la moneda principal y se mantienen por compatibilidad con versiones anteriores. Para cuentas multimoneda, itere sobre balances[].
Cómo se calculan los números (no son intercambiables):
balances[]yprimarycuentan solo las billeterasOPERATIONALactivas, sumadas por moneda:available = Σ(balance − heldBalance),held = Σ heldBalance,pending = Σ pendingBalance,total = available + held + pending.- Esta forma nunca devuelve
404: sin ninguna billetera obtiene ceros ybalances: []. - Un retiro individual se toma de una billetera, y la forma plana
?currency=de abajo lee solo la billetera predeterminada; por eso, para una moneda con varias billeteras,/balance,?currency=y la verificación del retiro pueden mostrar tres númerosavailabledistintos.
#Moneda única (forma heredada)
GET /v1/wallets/balance?currency=BRL
Pase currency para obtener la forma plana de moneda única:
curl "https://api.liqfy.com.br/v1/wallets/balance?currency=BRL" \
-H "Authorization: Bearer $LIQFY_API_KEY"{
"available": 880,
"held": 0,
"pending": 0,
"currency": "BRL",
"next_release_at": null,
"next_release_amount": null
}currency no distingue entre mayúsculas y minúsculas. Esta forma lee solo la billetera predeterminada de la cuenta para esa moneda (no una suma), y una moneda desconocida devuelve ceros en lugar de un error. Aquí no hay total/retained.
Autenticación y errores. Envíe siempre la clave de API. Una clave ausente o inválida →
401(nunca404). Sincurrencyesta ruta nunca devuelve404; con?currency=, un404not_foundsignifica que la cuenta no tiene ninguna billetera (no es un problema de enrutamiento). Una ruta incorrecta (/v1/wallets/balance, en plural, con el prefijo/v1) o un intermediario que no reenvía/v1/wallets/*nunca llega a Liqfy y se manifiesta como su propio error.
#Listar billeteras
GET /v1/wallets
Todas las billeteras de la cuenta — de cualquier walletType, activas e inactivas, posiblemente varias por moneda — con la misma autenticación. Un array JSON simple, sin paginación.
curl https://api.liqfy.com.br/v1/wallets \
-H "Authorization: Bearer $LIQFY_API_KEY"Respuesta 200 OK
[
{
"id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"currency": "BRL",
"label": "Operating wallet",
"walletType": "OPERATIONAL",
"isDefault": true,
"isActive": true,
"balance": 880,
"pendingBalance": 0,
"createdAt": "2026-04-25T15:42:11.000Z"
}
]balance/pendingBalance están en la unidad monetaria más pequeña. No son los mismos importes que GET /v1/wallets/balance expone como available/pending: balance ya incluye el importe retenido (available = balance − heldBalance en una billetera OPERATIONAL activa), pendingBalance coincide con pending solo en el caso de una única billetera, y esta lista no incluye heldBalance, por lo que available no se puede calcular a partir de ella.
#Obtener billetera
GET /v1/wallets/{id}
Una billetera por id (UUID). Cualquier tipo, activa o no, con ámbito en la cuenta del llamante.
curl https://api.liqfy.com.br/v1/wallets/a1b2c3d4-e5f6-4789-9abc-def012345678 \
-H "Authorization: Bearer $LIQFY_API_KEY"Respuesta 200 OK
{
"id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"currency": "BRL",
"walletType": "OPERATIONAL",
"label": "Operating wallet",
"isDefault": true,
"balance": 880,
"pendingBalance": 0,
"heldBalance": 0,
"isActive": true,
"createdAt": "2026-04-25T15:42:11.000Z",
"updatedAt": "2026-07-23T14:31:00.000Z"
}Un id desconocido, o de otra cuenta, responde 404 not_found.
#Operaciones de pago
/v1/payments. Estas rutas operan sobre el mismo cobro que creó mediante /v1/charges, identificado por su id sin procesar (sin el prefijo ch_). Cubren operaciones que la superficie /v1/charges aún no expone — cancelación, estadísticas, comprobantes, conciliación — además de crear/consultar/listar en el formato de transacción. Para crear un cobro, prefiera Cobros.
Los reembolsos no forman parte de la API del comercio: POST /payments/{id}/refund responde 403 a toda solicitud con clave de API (error.code "forbidden", mensaje con el prefijo del marcador REFUND_ADMIN_ONLY). Los reembolsos se emiten desde el panel de administración de Liqfy — consulte Reembolsos más abajo.
Las rutas internas de administración bajo /payments (por ejemplo GET /payments/{id}/provider-status) no forman parte de la API del comercio: llamadas con una clave de API responden 404, como si la ruta no existiera.
#Crear pago
POST /payments
Encabezados
| Encabezado | Obligatorio | Notas |
|---|---|---|
Authorization | sí | Bearer + su clave de API. |
Idempotency-Key | sí | Canal preferido. El campo del cuerpo idempotencyKey se acepta como alias: si se envían ambos deben coincidir (valores divergentes → 400); si no se envía ninguno → 400. |
Cuerpo
| Campo | Tipo | Obligatorio | Descripción |
|---|---|---|---|
amount | entero | sí | Unidad monetaria más pequeña, > 0. |
currency | cadena (3–8) | no | Valor predeterminado: "BRL". Ejemplos: BRL, EUR, USD, USDT. |
paymentMethods | cadena[] | sí, salvo con checkout | Uno o más de los 11 métodos: PIX, CRYPTO, CREDIT_CARD, BOLETO, MBWAY, MULTIBANCO, IDEAL, BANCONTACT, SEPA, BIZUM, SWAP_NOW. Con checkout es opcional y restringe los métodos de la plantilla. |
checkout | cadena | no | Slug de la plantilla de checkout alojado (1–80 caracteres). Un slug desconocido → 404; si el servicio de plantillas no está disponible → 503. |
customerId | cadena | no | Su id de usuario interno. Solo se reenvía con la solicitud: no se persiste y no se devuelve en las respuestas ni en los webhooks del comercio. |
customerName | cadena | no | |
customerDocument | cadena | no | CPF, CNPJ, NIF u otro identificador fiscal. |
customerEmail | cadena | no | Debe ser una dirección de correo electrónico válida. |
customerPhone | cadena | no | |
customer | objeto | no | { name?, document?, email?, phone? } anidado. Se aplana en los campos customer*; los campos planos prevalecen en caso de conflicto. |
expectedPayerDocument | cadena | no | Bloqueo de CPF/CNPJ del pagador, solo dígitos. |
items | objeto[] | no | { name, quantity, unitPrice, totalPrice } — todos enteros > 0 excepto name. |
metadata | objeto | no | Formato libre. Las claves returnUrl/cancelUrl dentro de él deben ser URLs http(s), pero los campos de primer nivel returnUrl/cancelUrl de abajo son las URLs de retorno. |
webhookUrl | cadena | no | Sobrescritura de la URL de webhook por transacción. Debe ser una URL válida. |
country | cadena | no | 2–3 caracteres. |
riskTier | enum | no | LOW, MEDIUM o HIGH. |
environment | enum | no | SANDBOX, STAGING o PRODUCTION. Si se omite, la plataforma lo deriva. Solo la clave decide adónde va realmente el cobro. |
returnUrl | cadena | no | Adónde vuelve el pagador después de pagar: URL http(s) sin espacios ni fragmento. |
cancelUrl | cadena | no | Adónde va el pagador al cancelar: misma regla de URL. Requiere returnUrl. |
expiresIn | entero | no | Validez del Pix en segundos, 60–604800. |
idempotencyKey | cadena | sí | Alias en el cuerpo del encabezado Idempotency-Key. Única por solicitud prevista; los reenvíos devuelven el original. |
Respuesta 201 Created
{
"id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"status": "WAITING_PAYMENT",
"amount": 24900,
"currency": "BRL",
"paymentMethods": ["PIX"],
"customerName": "Maria Silva",
"customerDocument": "12345678909",
"customerEmail": "maria@example.com",
"expectedPayerDocument": "12345678909",
"actualPayerDocument": null,
"payerValidationStatus": "PENDING",
"metadata": { "orderId": "ORD-7821" },
"checkoutUrl": "https://checkout.liqfy.com.br/c/a1b2c3d4-e5f6-4789-9abc-def012345678",
"createdAt": "2026-04-25T15:42:11.000Z"
}Los campos específicos del método (pixQrCode, mbEntity, boletoLine, cardRedirectUrl, …) ya vienen en la respuesta de creación cuando el método los produce de forma síncrona: el BR Code/QR de Pix, la entidad/referencia de Multibanco, el boleto y las redirecciones de tarjeta se devuelven en 201. Solo los artefactos que realmente llegan más tarde requieren un GET /payments/{id} posterior.
checkoutUrl está presente en la creación y en la consulta, y ausente en las filas de la lista y en la respuesta de cancelación. El grupo de validación del pagador es expectedPayerDocument (lo que usted bloqueó), actualPayerDocument (lo que informa el proveedor) y payerValidationStatus (NOT_REQUIRED, PENDING, MATCHED, MISMATCH, UNVERIFIED).
#Obtener pago
GET /payments/{id}
Respuesta 200 OK
{
"id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"status": "PAID",
"amount": 24900,
"currency": "BRL",
"paymentMethods": ["PIX"],
"paidWith": "PIX",
"pixQrCode": "data:image/png;base64,iVBOR...",
"pixCopyPaste": "00020126580014br.gov.bcb.pix...",
"pixExpiresAt": "2026-04-25T16:12:11.000Z",
"cardRedirectUrl": null,
"mbEntity": null,
"mbReference": null,
"mbExpiresAt": null,
"boletoBarcode": null,
"boletoLine": null,
"boletoPdfUrl": null,
"boletoExpiresAt": null,
"cryptoAddress": null,
"cryptoAmount": null,
"cryptoNetwork": null,
"cryptoCurrency": null,
"platformFee": 200,
"expectedPayerDocument": "12345678909",
"actualPayerDocument": "12345678909",
"payerValidationStatus": "MATCHED",
"metadata": { "orderId": "ORD-7821" },
"checkoutUrl": "https://checkout.liqfy.com.br/c/a1b2c3d4-e5f6-4789-9abc-def012345678",
"createdAt": "2026-04-25T15:42:11.000Z",
"paidAt": "2026-04-25T15:43:08.000Z"
}Los campos son null cuando no aplican al paymentMethods elegido.
Ninguna respuesta de /v1/payments (crear, consultar, listar, cancelar) indica qué adquirente atendió el cobro: provider, providerAccountId, providerTransactionId, providerFeeSource, cardClientSecret y tenantId no se devuelven (eliminados el 2026-10-12), ni tampoco el costo del adquirente (providerFee, netAmount). Una redirección de tarjeta o bancaria siempre llega como el enlace /c/{id} del checkout.
#Listar pagos
GET /payments
Parámetros de consulta
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
page | int | 1 | |
limit | int | 20 | Máximo 100. |
status | enum | — | Consulte Enum de estados más abajo. |
currency | cadena | — | Filtrar por moneda. |
startDate | ISO 8601 | — | Límite inferior inclusivo sobre createdAt. |
endDate | ISO 8601 | — | Límite superior inclusivo sobre createdAt. |
source | enum | — | API, PANEL, MANUAL o INDEFINIDO (filas sin origen). |
sortBy | cadena | createdAt | Un nombre de columna de transacción (createdAt, amount, status, paidAt, updatedAt, …). Un nombre desconocido es un 500, no un 400: limítese a columnas reales. |
sortOrder | enum | desc | asc o desc. |
Respuesta 200 OK
{
"data": [ { "id": "a1b2c3d4-e5f6-4789-9abc-def012345678", "...": "..." } ],
"total": 142,
"page": 1,
"limit": 20
}Las filas de la lista no incluyen checkoutUrl. Este es un sobre paginado (total/page/limit): la paginación por cursor está en GET /v1/charges.
#Estadísticas
GET /payments/stats?days=7
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
days | int | 7 | Días hábiles en la timeZone, incluido hoy. |
from/to | ISO 8601 | — | Ventana explícita; sustituye a days cuando está presente. |
timeZone | cadena | America/Sao_Paulo | Nombre de zona horaria IANA. Un nombre inválido → 400. |
days=7 = hoy más los seis días naturales anteriores. Los totales (totalTransactions, paidTransactions, successRate, volumeByCurrency, methodBreakdown) cubren toda la ventana, sea cual sea su duración. dailyVolume tiene un punto por día natural y como máximo 366 puntos: para una ventana más larga contiene los 366 días más recientes. hourlyVolume está presente solo cuando la ventana es de un único día — un punto por hora hábil, con la misma clave que dailyVolume pero con la hora añadida ("YYYY-MM-DDTHH"). methodBreakdownByCurrency tiene una fila plana por cada par (método, moneda). Se excluyen los cobros de sandbox/prueba. Siempre con ámbito en su cuenta: una solicitud cuya cuenta no puede resolverse responde 401.
Respuesta 200 OK
{
"totalTransactions": 142,
"paidTransactions": 119,
"todayTransactions": 8,
"successRate": 84,
"volumeByCurrency": [
{ "currency": "BRL", "volume": 1245000, "count": 95 },
{ "currency": "EUR", "volume": 89400, "count": 24 }
],
"todayVolumeByCurrency": { "BRL": 24900, "EUR": 8990 },
"dailyVolume": [
{ "date": "2026-04-19", "currencies": { "BRL": 89000 } },
{ "date": "2026-04-20", "currencies": { "BRL": 124500, "EUR": 4500 } }
],
"hourlyVolume": [
{ "date": "2026-04-20T09", "currencies": { "BRL": 24900 } }
],
"methodBreakdown": [
{ "method": "PIX", "volume": 980000, "count": 78 },
{ "method": "CREDIT_CARD", "volume": 265000, "count": 34 },
{ "method": "MULTIBANCO", "volume": 89400, "count": 7 }
],
"methodBreakdownByCurrency": [
{ "method": "PIX", "currency": "BRL", "volume": 980000, "count": 78 },
{ "method": "CREDIT_CARD", "currency": "BRL", "volume": 265000, "count": 34 },
{ "method": "MULTIBANCO", "currency": "EUR", "volume": 89400, "count": 7 }
],
"statusCounts": { "PAID": 119, "REFUSED": 10 },
"avgPaySeconds": 42
}#Métricas
GET /payments/metrics?days=7¤cy=BRL
Métricas de embudo de conversión y de volumen para su cuenta de comercio. days tiene como valor predeterminado 7 (misma regla de ventana que Estadísticas, sin el límite de 366 puntos); currency es opcional (filtra a una sola moneda); timeZone funciona como en Estadísticas. Con ámbito en su clave de API: sin una cuenta resoluble responde 401, nunca cifras de toda la plataforma.
Respuesta 200 OK
{
"days": 7,
"currency": "BRL",
"overall": { "created": 142, "paid": 119, "conversionRate": 83.8 },
"byMethod": [
{ "method": "PIX", "created": 90, "paid": 78, "conversionRate": 86.7 }
],
"refunds": { "count": 2, "volumeByCurrency": { "BRL": 4500 } },
"chargebacks": { "count": 0 }
}#Volumen neto
GET /payments/net-volume
Volumen neto liquidado (amount − platformFee, solo PAID) para una ventana.
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
from/to | ISO 8601 | — | Límites de la ventana. |
timeZone | cadena | America/Sao_Paulo | Nombre de zona horaria IANA. Un nombre inválido → 400. |
Respuesta 200 OK
{
"from": "2026-04-19T00:00:00.000Z",
"to": "2026-04-25T23:59:59.999Z",
"byCurrency": {
"BRL": { "netVolume": 1220500, "txCount": 95, "grossVolume": 1245000, "feeTotal": 24500 }
}
}#Conversión
GET /payments/conversion
Filas de { currency, status, count, volume } para el embudo por estado: cobros creados desde from, en el estado consultado, excluidos los cobros de prueba.
| Parámetro | Tipo | Predeterminado | Descripción |
|---|---|---|---|
from | ISO 8601 | — | Límite inferior inclusivo. Un valor inválido → 400. |
Respuesta 200 OK
[
{ "currency": "BRL", "status": "PAID", "count": 95, "volume": 1245000 },
{ "currency": "BRL", "status": "REFUSED", "count": 4, "volume": 12000 }
]#Reembolsos (solo desde el panel de administración)
POST /payments/{id}/refund
No se puede llamar con una clave de API. Toda solicitud del comercio se rechaza con 403, sea cual sea el cuerpo: error.code es "forbidden" y el mensaje comienza con el marcador REFUND_ADMIN_ONLY (un prefijo de mensaje, no un código — consulte Errores). Los reembolsos (totales o parciales, PIX o tarjeta) se solicitan desde el panel de administración de Liqfy, que primero aplica la retención en la billetera y luego ejecuta el reembolso. El comercio puede seguir el estado de un reembolso en GET /payments/{id}/refunds y en el webhook charge.refunded.
El cuerpo documentado para el llamante interno — idempotencyKey, amount, reason, strategy (devolution/cashout), passFeeToTenant, destinationKey, refundId — no es un contrato para el comercio; no desarrolle sobre él.
#Listar reembolsos
GET /payments/{id}/refunds
Devuelve todos los reembolsos emitidos contra una transacción (los más recientes primero). No se devuelve el id de reembolso del adquirente.
[
{
"id": "b2c3d4e5-f6a7-4890-9abc-def012345678",
"transactionId": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"amount": 24900,
"currency": "BRL",
"reason": null,
"failureReason": null,
"status": "REFUNDED",
"origin": "MERCHANT",
"idempotencyKey": "order-7821",
"refundedAt": "2026-04-25T15:50:00.000Z",
"createdAt": "2026-04-25T15:50:00.000Z",
"updatedAt": "2026-04-25T16:12:00.000Z"
}
]status es uno de PENDING, IN_PROGRESS, PENDING_RECONCILIATION, REFUNDED, FAILED; origin es MERCHANT, AUTOMATIC_PAYER_RESTRICTION o REVIEW_REJECTION. reason solo se completa para reembolsos originados por el comercio; para los reembolsos abiertos por la plataforma (AUTOMATIC_PAYER_RESTRICTION, REVIEW_REJECTION) siempre es null. failureReason siempre es null para el comercio: un reembolso fallido se indica mediante status: "FAILED".
#Cancelar pago
POST /payments/{id}/cancel
Cancela un cobro en curso — válido solo mientras WAITING_PAYMENT o PENDING. PROCESSING se rechaza con 409 payment_not_cancellable, y cualquier otro estado con 400. Los cobros liquidados (PAID/APPROVED) deben reembolsarse, no cancelarse. Devuelve la transacción actualizada con la misma forma que GET /payments/{id} (sin checkoutUrl) y publica el evento charge.failed, con status: "CANCELLED" y previousStatus.
#Reenviar webhook
POST /payments/{id}/resend-webhook
Vuelve a emitir el estado actual de la transacción como una nueva entrega de webhook: útil cuando su endpoint estuvo caído.
{ "resent": true, "status": "PAID" }#Conciliar
POST /payments/{id}/reconcile
Solicita a la plataforma que vuelva a verificar la transacción con el proveedor y resuelva cualquier discrepancia.
Respuesta 200 OK
{ "reconciled": true, "status": "PAID" }Una transacción ya en estado terminal responde { "reconciled": false, "status": "…" }. Los motivos internos y los estados del proveedor no forman parte de la respuesta al comercio: solo se devuelven reconciled y status.
#Confirmar pago de sandbox
POST /payments/{id}/confirm-sandbox
El mecanismo de autoprueba del comercio para webhooks de extremo a extremo: en una transacción creada con una clave de prueba, esto pasa el cobro simulado a PAID y dispara los webhooks normales. Nunca acredita una billetera. Consulte Sandbox.
Respuesta 200 OK
{ "confirmed": true, "status": "PAID" }Un cobro ya en estado terminal responde { "confirmed": false, "status": "…", "reason": "ALREADY_TERMINAL" }. Un cobro que no es una transacción de sandbox/prueba se rechaza con 400.
#Comprobante
GET /payments/{id}/receipt
Documento propio de Liqfy (PDF) para una transacción con resultado final: nunca el documento del adquirente, y nunca nombra al proveedor. Las transacciones en curso responden 400.
{ "contentType": "application/pdf", "base64": "JVBERi0xLjcK..." }Solo existe un documento para estos resultados, y su título depende del resultado:
| Estado | Título del documento |
|---|---|
PAID / APPROVED | Comprovante de Pagamento PIX — el único comprobante de pago; incluye el id E2E del BACEN cuando se conoce. |
EXPIRED | Cobrança Expirada |
REFUSED | Cobrança Não Aprovada |
REFUNDED | Comprovante de Devolução |
CANCELLED | Cobrança Cancelada |
CHARGEBACK | Pagamento em Devolução |
Todo documento que no sea de pago indica que no es prueba de pago y explica al cliente final qué ocurrió y qué hacer a continuación. Los documentos del pagador se muestran enmascarados.
#Webhooks
#Registrar endpoint
POST /webhooks/endpoints
{
"url": "https://merchant.example.com/hooks/liqfy",
"events": ["charge.paid", "charge.failed", "charge.expired"]
}Nombres de eventos (relacionados con cobros): charge.created, charge.paid, charge.failed, charge.expired, charge.refunded, payout.created, payout.approved, payout.paid, payout.failed, además de med_case.created y med_case.updated. Se entregan en el sobre versionado evt_ y firmados con X-Liqfy-Signature: t=<unix>,v1=<hex> — consulte Webhooks. Suscríbase a estos. (med.resolved pertenece a la misma familia, pero viaja en el sobre anterior { event, data } con la firma sha256=).
Solo se aceptan nombres canónicos de eventos de cobro y de retiro. Los nombres retirados devuelven HTTP 400 LEGACY_WEBHOOK_EVENT con el replacement canónico. Las suscripciones existentes se migran y se deduplican.
Respuesta 201 Created
{
"id": "e5f6a7b8-c9d0-4123-9ef0-123456789012",
"url": "https://merchant.example.com/hooks/liqfy",
"events": ["charge.paid", "charge.failed", "charge.expired"],
"secret": "b8f3a9c1d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a1",
"status": "ACTIVE"
}secret se muestra una sola vez: guárdelo de inmediato. Fuera de sandbox/staging la URL debe ser https:// y no puede apuntar a un dominio Liqfy; una URL duplicada responde 409, y la cuenta tiene un número limitado de endpoints activos.
#Listar endpoints
GET /webhooks/endpoints
{
"data": [
{
"id": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"url": "https://...",
"events": ["payment.status_changed"],
"status": "ACTIVE",
"createdAt": "...",
"updatedAt": "..."
}
],
"access": { "canManage": true },
"httpsOnly": true
}Los ids son UUID. access.canManage indica si el llamante puede escribir endpoints; httpsOnly indica si la plataforma exige actualmente URLs https://.
secret nunca es devuelto por este endpoint.
#Probar endpoint
POST /webhooks/endpoints/{id}/test
Envía una muestra canónica síncrona de charge.paid con el sobre versionado y la firma con marca de tiempo. Al superar el límite horario de pruebas se devuelve 429 WEBHOOK_TEST_RATE_LIMIT.
{
"ok": true,
"statusCode": 200,
"durationMs": 143,
"errorKind": null,
"error": null,
"responseSnippet": "{\"received\":true}",
"eventType": "charge.paid",
"url": "https://merchant.example.com/hooks/liqfy",
"sentHeaders": { "X-Liqfy-Event-Type": "charge.paid" },
"sentPayload": { "id": "evt_...", "object": "event", "...": "..." }
}errorKind es timeout, connection o http cuando ok es false.
#Rotar secreto
POST /webhooks/endpoints/{id}/rotate-secret
{ "id": "e5f6a7b8-c9d0-4123-9ef0-123456789012" }Respuesta 200 OK
{ "id": "e5f6a7b8-c9d0-4123-9ef0-123456789012", "secret": "<64-char hex>" }El nuevo secreto se muestra una sola vez. La rotación es un intercambio instantáneo en el servidor: no hay ventana de superposición. Todo webhook firmado después de esta llamada usa el nuevo secreto, así que haga que su verificador acepte tanto el secreto antiguo como el nuevo durante su despliegue y luego descarte el antiguo (consulte webhooks.md).
#Actualizar endpoint
PATCH /webhooks/endpoints/{id}
Actualice la URL, los eventos suscritos o el estado (ACTIVE/INACTIVE). Envíe solo los campos que desea cambiar.
{ "url": "https://merchant.example.com/hooks/v2", "status": "ACTIVE" }Respuesta 200 OK — { id, url, events, status }. El secreto nunca se devuelve.
#Eliminar endpoint
DELETE /webhooks/endpoints/{id}
Elimina el endpoint de forma permanente. Las entregas pendientes hacia él se redirigen a los demás endpoints activos de la cuenta; solo se cancelan cuando no queda ninguno. El historial de entregas se conserva.
Respuesta 200 OK — { "deleted": true }.
#Catálogo de eventos
GET /webhooks/event-catalog
Devuelve la lista completa y actual de nombres de eventos públicos a los que es posible suscribirse, con sus descripciones. Esta ruta está protegida por la misma autenticación por clave de API que el resto de /v1/webhooks. Extracto relevante para cobros/retiros:
[
{ "event": "charge.created", "description": "Cobrança criada (Pix/cartão gerado, aguardando pagamento)." },
{ "event": "charge.paid", "description": "Cobrança paga e confirmada (Pix/cartão liquidado)." },
{ "event": "charge.failed", "description": "Cobrança falhou ou foi cancelada." },
{ "event": "charge.expired", "description": "Cobrança expirou sem pagamento." },
{ "event": "charge.refunded","description": "Cobrança reembolsada." },
{ "event": "payout.created", "description": "Saque solicitado." },
{ "event": "payout.approved", "description": "Payout approved." },
{ "event": "payout.paid", "description": "Saque liquidado com sucesso." },
{ "event": "payout.failed", "description": "Saque falhou ou foi rejeitado." }
]#Listar entregas
GET /webhooks/deliveries
| Parámetro | Descripción |
|---|---|
status | PENDING, PROCESSING, DELIVERED, FAILED, CANCELLED |
eventType | Filtrar por nombre de evento (charge.paid, charge.refunded, …). |
endpointId | Filtrar por endpoint registrado. |
limit | Predeterminado 25, máximo 100. |
offset | Predeterminado 0. |
{
"data": [
{
"id": "b2c3d4e5-f6a7-4890-9abc-def012345678",
"endpointId": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"eventType": "charge.paid",
"status": "DELIVERED",
"attempts": 1,
"maxAttempts": 15,
"lastStatusCode": 200,
"lastError": null,
"nextRetryAt": null,
"deliveredAt": "2026-04-25T15:43:09.000Z",
"createdAt": "2026-04-25T15:43:08.000Z",
"updatedAt": "2026-04-25T15:43:09.000Z",
"payload": { "type": "charge.paid", "object": "event", "data": { "object": { "id": "ch_example", "object": "charge", "status": "paid" } } }
}
],
"total": 142,
"limit": 25,
"offset": 0
}Las filas incluyen payload y lastError, no el cuerpo de la respuesta: eso está en el detalle de la entrega, más abajo.
#Obtener entrega
GET /webhooks/deliveries/{id}
La entrega completa, incluidos el cuerpo de la respuesta y el registro de intentos.
{
"id": "b2c3d4e5-f6a7-4890-9abc-def012345678",
"endpointId": "a1b2c3d4-e5f6-4789-9abc-def012345678",
"eventType": "charge.paid",
"status": "FAILED",
"attempts": 3,
"maxAttempts": 15,
"lastStatusCode": 502,
"lastError": "HTTP 502",
"lastResponseBody": "Bad Gateway",
"logs": [
{
"id": "c3d4e5f6-a7b8-4901-9abc-def012345678",
"deliveryId": "b2c3d4e5-f6a7-4890-9abc-def012345678",
"attempt": 1,
"statusCode": 502,
"error": "HTTP 502",
"responseBody": "Bad Gateway",
"duration": 312,
"url": "https://merchant.example.com/hooks/liqfy",
"createdAt": "2026-04-25T15:43:09.000Z"
}
],
"endpoint": { "url": "https://merchant.example.com/hooks/liqfy", "status": "ACTIVE" }
}#Reenviar entrega
POST /webhooks/deliveries/{id}/replay
Vuelve a encolar una entrega (reinicia los intentos y la programación). Una entrega DELIVERED se rechaza con 400, y una PROCESSING con 400: espere y vuelva a intentarlo.
{ "id": "b2c3d4e5-f6a7-4890-9abc-def012345678", "status": "PENDING", "attempts": 0, "nextRetryAt": "2026-04-25T16:08:00.000Z" }#Reenviar entregas en lote
POST /webhooks/deliveries/replay-bulk
{ "status": "FAILED", "endpointId": "a1b2c3d4-e5f6-4789-9abc-def012345678", "limit": 50 }| Parámetro | Descripción |
|---|---|
status | Estado objetivo. Predeterminado FAILED + CANCELLED. Valor desconocido → 400. |
endpointId | Restringir a un endpoint. |
limit | Predeterminado 50, máximo 500. |
Respuesta 200 OK — { "requeued": 12 }.
#Obtener eventos (pull)
GET /webhooks/events
Vista de conciliación de los eventos, con paginación keyset: { data, nextCursor } (observe el camelCase nextCursor). Las filas son { eventType, payload, status, lastStatusCode, deliveredAt, createdAt } — sin id por fila.
| Parámetro | Descripción |
|---|---|
since/until | Límites ISO 8601 sobre createdAt. |
status | Filtro por estado de entrega. |
eventType | Filtro por nombre de evento. |
limit | Predeterminado 50, máximo 100. |
cursor | Cursor opaco de nextCursor. |
#Estadísticas de entregas
GET /webhooks/stats
{
"total": 1402,
"PENDING": 3,
"PROCESSING": 1,
"DELIVERED": 1380,
"FAILED": 12,
"CANCELLED": 6
}#Enum de estados
La tabla siguiente es el enum de estados detallado que devuelven las rutas de transacción /v1/payments (y eventType/payload.data.status en sus entregas de webhook). POST/GET /v1/charges nunca emiten estos valores; emiten el vocabulario público más reducido (pending, processing, paid, failed, expired, cancelled, refunded, disputed — consulte Primeros pasos §5), al que se asigna el enum siguiente.
| Estado de la transacción | Descripción | charge.status público |
|---|---|---|
PENDING | Interno — en creación. Rara vez se expone. | pending |
WAITING_PAYMENT | En espera de una acción del cliente. | pending |
PROCESSING | Tarjeta / 3DS en curso. | processing |
PAID | Liquidado — métodos que no son tarjeta. | paid |
APPROVED | Liquidado — métodos de tarjeta. | paid |
REFUSED | Rechazado por el adquirente o el emisor. | failed |
CANCELLED | Cancelado antes de completarse. | cancelled |
EXPIRED | Venció la ventana de tiempo. | expired |
REFUNDED | Reembolsado por completo. | refunded |
CHARGEBACK | El emisor inició un contracargo (tarjetas). | disputed |
DISPUTE | Disputa abierta: disputa del titular de la tarjeta (tarjetas) o un caso MED de Pix sobre un cobro Pix pagado. Un MED ganado o retirado devuelve el cobro a PAID. | disputed |
charge.paid representa un cobro pagado. charge.failed y charge.expired distinguen fallo y vencimiento. Un cobro Pix que pasa a DISPUTE a causa de un MED no emite un webhook charge.*: el MED se sigue a través del caso MED (consulte metadata.med.caseId en Obtener cobro).
#Esquema del payload de webhook
#Sobre canónico (charge.* / payout.*)
{
"id": "evt_5f3a9b2c1d4e5f6a7b8c9d0e1f2a3b4c",
"object": "event",
"api_version": "2026-07-23",
"type": "charge.paid",
"created_at": "2026-07-23T14:31:00.000Z",
"data": {
"object": {
"id": "ch_a1b2c3d4-0000-0000-0000-000000000009",
"object": "charge",
"amount": 24900,
"currency": "BRL",
"status": "paid",
"payment_method": "pix",
"settlement": {}
}
}
}| Campo | Siempre presente | Descripción |
|---|---|---|
id | sí | evt_… — estable por evento de negocio, idéntico entre reintentos. Deduplique con este valor. |
object | sí | Siempre "event". |
api_version | sí | Versión del contrato, p. ej. 2026-07-23. |
type | sí | charge.created | charge.paid | charge.failed | charge.expired | charge.refunded | payout.created | payout.approved | payout.paid | payout.failed | med_case.created | med_case.updated. payout.approved = retiro aprobado, pendiente de liquidación (processing). |
data.object | sí | El objeto público del evento — mismo serializador y nombres de campo que la superficie REST para charge/payout, con las reducciones específicas de cada evento descritas en Webhooks. |
#Encabezados de webhook
| Encabezado | Descripción |
|---|---|
X-Liqfy-Signature | Eventos charge.*/payout.*: HMAC t=<unix>,v1=<hex> de "<t>.<rawBody>". Eventos de KYC, ciclo de vida de la cuenta y med.resolved: HMAC sha256=<hex> del cuerpo sin procesar. |
X-Liqfy-Delivery-Id | Único por entrega — idéntico en todos los reintentos de esa entrega; úselo para la deduplicación a nivel de transporte. |
X-Liqfy-Event-Type | Refleja type / event. |
Consulte webhooks.md para ver ejemplos de verificación.
#Códigos de estado HTTP
| Código | Uso |
|---|---|
200 | Lectura correcta |
201 | Recurso creado |
204 | Sin contenido (p. ej., cierre de sesión) |
400 | Error de validación, o una escritura financiera sin Idempotency-Key (o con claves divergentes entre encabezado y cuerpo en /v1/payments) |
401 | Clave de API ausente / inválida |
403 | Bloqueado por la protección contra fraude / velocidad — fraud.tenant_velocity_exceeded (demasiados intentos de cobro desde la cuenta en un intervalo corto) o fraud.customer_velocity_exceeded (demasiados para el mismo documento o correo electrónico del cliente; los cobros vencidos y cancelados no cuentan) —, un intento de reembolso con clave de API (marcador de mensaje REFUND_ADMIN_ONLY, no un código), account_suspended, o la lista de IPs permitidas (solo rutas de cuenta — billeteras, retiros, transacciones, MED, api-keys; no payments/charges/webhooks) |
404 | Recurso no encontrado |
409 | Conflicto — idempotency_key_reused, idempotency_key_in_flight, payment_not_cancellable |
422 | Creación de cobro rechazada por el enrutamiento/configuración del proveedor. Se transmiten el estado 4xx y un code estable: NO_PROVIDER_CONFIGURED, UNKNOWN_METHOD, PAYMENT_REJECTED, MOCK_PROVIDER_IN_PRODUCTION, PAYER_IDENTITY_REQUIRED, PAYER_NAME_REQUIRED |
429 | Límite de tasa excedido |
500 | Error del servidor — es seguro reintentar (la idempotencia protege) |
503 | Adquirente upstream no disponible (PROVIDER_UNAVAILABLE) — reintente con backoff |
Los mensajes de error de creación de cobros son textos neutros propios de Liqfy: nunca incluyen el nombre del proveedor, sus códigos internos ni la configuración de la cuenta. Una respuesta inesperada del upstream se informa como PROVIDER_ERROR. Indique el request_id al soporte para obtener el detalle.
Consulte Errores para ver el sobre de error canónico completo (error.type/error.code/error.message, request_id, X-Request-Id).