Skip to content
LIQFYdocs
PTENENEN
Go to dashboard

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", ids ch_…, encabezado Idempotency-Key, bloque pix. 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 prefijo ch_). 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

EncabezadoObligatorioNotas
AuthorizationsíBearer + su clave de API (lq_test_* / lq_live_*). El encabezado heredado apikey se sigue aceptando.
Idempotency-KeysíCualquier cadena no vacía, con ámbito por (merchant, key). Es una escritura financiera: omitirlo produce un 400.

Cuerpo

CampoTipoObligatorioDescripción
amountenterosíUnidad monetaria más pequeña, > 0.
currencycadenanoCódigo ISO 4217 de 3 letras, convertido a mayúsculas por la API. Valor predeterminado: "BRL". Los cobros Pix deben usar BRL.
payment_methodcadenasí"pix" — el único valor aceptado hoy.
descriptioncadenanoHasta 500 caracteres; se incorpora a metadata.description en la lectura.
expires_inenteronoValidez 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.namecadenano
customer.documentcadenanoCPF o CNPJ.
customer.emailcadenanoDebe ser una dirección de correo electrónico válida.
customer.phonecadenano
expected_payer_tax_idcadenanoVincula 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.
metadataobjetonoFormato libre; se eliminan las claves reservadas o con prefijo de guion bajo.

Ejemplo

bash
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

json
{
  "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.

http
GET /v1/charges?limit=25&starting_after=ch_01J…&status=paid
ParámetroTipoPredeterminadoDescripción
limitentero251–100.
starting_aftercadena—Un id de cobro (ch_…) del mismo recurso: cursor, no un offset. Hasta 140 caracteres.
statusenum—Vocabulario público de estados (pending, paid, …).
created_afterISO 8601—Límite inferior inclusivo sobre created_at.
created_beforeISO 8601—Límite superior inclusivo sobre created_at.
customer_idcadena—Filtra por documento del pagador. Hasta 140 caracteres.
idempotency_keycadena—Filtra por la Idempotency-Key usada en la creación (1–255 caracteres, recortados).
json
{
  "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:

bash
curl "https://api.liqfy.com.br/v1/wallets/balance" \
  -H "Authorization: Bearer $LIQFY_API_KEY"

Respuesta 200 OK

json
{
  "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 }
}
CampoDescripción
availableSaldo 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.
heldImporte retenido (bloqueado en tránsito) en las entradas balances[]/primary. No está presente en el nivel superior.
pendingLiquidado 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.
totalavailable + held + pending de la moneda principal.
retainedTotal bajo retención (retenciones PENDING) de la moneda principal. No incluye las retenciones por reembolso.
currencyMoneda principal (ISO 4217). Valor predeterminado: BRL.
next_release_atCadena ISO 8601 del momento en que se libera el próximo tramo pending, o null cuando no hay nada programado.
next_release_amountImporte de esa próxima liberación (unidad monetaria más pequeña), o null.
balances[]Una entrada por moneda: { currency, available, held, pending, total }.
primaryLa 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[] y primary cuentan solo las billeteras OPERATIONAL activas, sumadas por moneda: available = Σ(balance − heldBalance), held = Σ heldBalance, pending = Σ pendingBalance, total = available + held + pending.
  • Esta forma nunca devuelve 404: sin ninguna billetera obtiene ceros y balances: [].
  • 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úmeros available distintos.

#Moneda única (forma heredada)

GET /v1/wallets/balance?currency=BRL

Pase currency para obtener la forma plana de moneda única:

bash
curl "https://api.liqfy.com.br/v1/wallets/balance?currency=BRL" \
  -H "Authorization: Bearer $LIQFY_API_KEY"
json
{
  "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 (nunca 404). Sin currency esta ruta nunca devuelve 404; con ?currency=, un 404 not_found significa 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.

bash
curl https://api.liqfy.com.br/v1/wallets \
  -H "Authorization: Bearer $LIQFY_API_KEY"

Respuesta 200 OK

json
[
  {
    "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.

bash
curl https://api.liqfy.com.br/v1/wallets/a1b2c3d4-e5f6-4789-9abc-def012345678 \
  -H "Authorization: Bearer $LIQFY_API_KEY"

Respuesta 200 OK

json
{
  "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

EncabezadoObligatorioNotas
AuthorizationsíBearer + su clave de API.
Idempotency-Keysí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

CampoTipoObligatorioDescripción
amountenterosíUnidad monetaria más pequeña, > 0.
currencycadena (3–8)noValor predeterminado: "BRL". Ejemplos: BRL, EUR, USD, USDT.
paymentMethodscadena[]sí, salvo con checkoutUno 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.
checkoutcadenanoSlug de la plantilla de checkout alojado (1–80 caracteres). Un slug desconocido → 404; si el servicio de plantillas no está disponible → 503.
customerIdcadenanoSu 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.
customerNamecadenano
customerDocumentcadenanoCPF, CNPJ, NIF u otro identificador fiscal.
customerEmailcadenanoDebe ser una dirección de correo electrónico válida.
customerPhonecadenano
customerobjetono{ name?, document?, email?, phone? } anidado. Se aplana en los campos customer*; los campos planos prevalecen en caso de conflicto.
expectedPayerDocumentcadenanoBloqueo de CPF/CNPJ del pagador, solo dígitos.
itemsobjeto[]no{ name, quantity, unitPrice, totalPrice } — todos enteros > 0 excepto name.
metadataobjetonoFormato 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.
webhookUrlcadenanoSobrescritura de la URL de webhook por transacción. Debe ser una URL válida.
countrycadenano2–3 caracteres.
riskTierenumnoLOW, MEDIUM o HIGH.
environmentenumnoSANDBOX, STAGING o PRODUCTION. Si se omite, la plataforma lo deriva. Solo la clave decide adónde va realmente el cobro.
returnUrlcadenanoAdónde vuelve el pagador después de pagar: URL http(s) sin espacios ni fragmento.
cancelUrlcadenanoAdónde va el pagador al cancelar: misma regla de URL. Requiere returnUrl.
expiresInenteronoValidez del Pix en segundos, 60–604800.
idempotencyKeycadenasíAlias en el cuerpo del encabezado Idempotency-Key. Única por solicitud prevista; los reenvíos devuelven el original.

Respuesta 201 Created

json
{
  "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

json
{
  "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ámetroTipoPredeterminadoDescripción
pageint1
limitint20Máximo 100.
statusenum—Consulte Enum de estados más abajo.
currencycadena—Filtrar por moneda.
startDateISO 8601—Límite inferior inclusivo sobre createdAt.
endDateISO 8601—Límite superior inclusivo sobre createdAt.
sourceenum—API, PANEL, MANUAL o INDEFINIDO (filas sin origen).
sortBycadenacreatedAtUn 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.
sortOrderenumdescasc o desc.

Respuesta 200 OK

json
{
  "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ámetroTipoPredeterminadoDescripción
daysint7Días hábiles en la timeZone, incluido hoy.
from/toISO 8601—Ventana explícita; sustituye a days cuando está presente.
timeZonecadenaAmerica/Sao_PauloNombre 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

json
{
  "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&currency=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

json
{
  "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ámetroTipoPredeterminadoDescripción
from/toISO 8601—Límites de la ventana.
timeZonecadenaAmerica/Sao_PauloNombre de zona horaria IANA. Un nombre inválido → 400.

Respuesta 200 OK

json
{
  "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ámetroTipoPredeterminadoDescripción
fromISO 8601—Límite inferior inclusivo. Un valor inválido → 400.

Respuesta 200 OK

json
[
  { "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.

json
[
  {
    "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.

json
{ "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

json
{ "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

json
{ "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.

json
{ "contentType": "application/pdf", "base64": "JVBERi0xLjcK..." }

Solo existe un documento para estos resultados, y su título depende del resultado:

EstadoTítulo del documento
PAID / APPROVEDComprovante de Pagamento PIX — el único comprobante de pago; incluye el id E2E del BACEN cuando se conoce.
EXPIREDCobrança Expirada
REFUSEDCobrança Não Aprovada
REFUNDEDComprovante de Devolução
CANCELLEDCobrança Cancelada
CHARGEBACKPagamento 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

json
{
  "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

json
{
  "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

json
{
  "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.

json
{
  "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

json
{ "id": "e5f6a7b8-c9d0-4123-9ef0-123456789012" }

Respuesta 200 OK

json
{ "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.

json
{ "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:

json
[
  { "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ámetroDescripción
statusPENDING, PROCESSING, DELIVERED, FAILED, CANCELLED
eventTypeFiltrar por nombre de evento (charge.paid, charge.refunded, …).
endpointIdFiltrar por endpoint registrado.
limitPredeterminado 25, máximo 100.
offsetPredeterminado 0.
json
{
  "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.

json
{
  "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.

json
{ "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

json
{ "status": "FAILED", "endpointId": "a1b2c3d4-e5f6-4789-9abc-def012345678", "limit": 50 }
ParámetroDescripción
statusEstado objetivo. Predeterminado FAILED + CANCELLED. Valor desconocido → 400.
endpointIdRestringir a un endpoint.
limitPredeterminado 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ámetroDescripción
since/untilLímites ISO 8601 sobre createdAt.
statusFiltro por estado de entrega.
eventTypeFiltro por nombre de evento.
limitPredeterminado 50, máximo 100.
cursorCursor opaco de nextCursor.

#Estadísticas de entregas

GET /webhooks/stats

json
{
  "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ónDescripcióncharge.status público
PENDINGInterno — en creación. Rara vez se expone.pending
WAITING_PAYMENTEn espera de una acción del cliente.pending
PROCESSINGTarjeta / 3DS en curso.processing
PAIDLiquidado — métodos que no son tarjeta.paid
APPROVEDLiquidado — métodos de tarjeta.paid
REFUSEDRechazado por el adquirente o el emisor.failed
CANCELLEDCancelado antes de completarse.cancelled
EXPIREDVenció la ventana de tiempo.expired
REFUNDEDReembolsado por completo.refunded
CHARGEBACKEl emisor inició un contracargo (tarjetas).disputed
DISPUTEDisputa 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.*)

json
{
  "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": {}
    }
  }
}
CampoSiempre presenteDescripción
idsíevt_… — estable por evento de negocio, idéntico entre reintentos. Deduplique con este valor.
objectsíSiempre "event".
api_versionsíVersión del contrato, p. ej. 2026-07-23.
typesí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.objectsí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

EncabezadoDescripción
X-Liqfy-SignatureEventos 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-TypeRefleja type / event.

Consulte webhooks.md para ver ejemplos de verificación.

#Códigos de estado HTTP

CódigoUso
200Lectura correcta
201Recurso creado
204Sin contenido (p. ej., cierre de sesión)
400Error de validación, o una escritura financiera sin Idempotency-Key (o con claves divergentes entre encabezado y cuerpo en /v1/payments)
401Clave de API ausente / inválida
403Bloqueado 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)
404Recurso no encontrado
409Conflicto — idempotency_key_reused, idempotency_key_in_flight, payment_not_cancellable
422Creació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
429Límite de tasa excedido
500Error del servidor — es seguro reintentar (la idempotencia protege)
503Adquirente 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).