Skip to content
LIQFYdocs
PTENENEN
Go to dashboard

SDKs oficiales

Liqfy publica clientes oficiales para Node.js, Python, PHP y .NET. Envuelven la misma API REST /v1 descrita en la Referencia de la API: todo lo que puedes hacer con curl, puedes hacerlo sin un SDK. Lo que aportan los SDKs es la parte en la que es fácil equivocarse de forma sutil: la idempotencia, la política de reintentos y la verificación de firmas de webhooks.

Los cuatro comparten una misma versión: 0.8.0.

LenguajePaqueteInstalaciónEntorno de ejecución
Node.js / TypeScript@liqfy/nodenpm i @liqfy/nodeNode 18+
Pythonliqfypip install liqfyPython 3.8+
PHPliqfy/sdk-phpcomposer require liqfy/sdk-phpPHP 8.1+
.NET / C#Liqfydotnet add package Liqfynetstandard2.0, net8.0

#Lo que garantiza cada SDK

Los cuatro clientes son idénticos en comportamiento, no simplemente parecidos. En particular, la verificación de firmas de webhooks se ejecuta en CI contra un conjunto compartido de vectores de prueba: si Node acepta una firma, Python, PHP y .NET aceptan la misma, byte a byte.

#Familias de recursos

Cada cliente expone las mismas seis familias de recursos: mismas rutas y mismos formatos en el cable que la Referencia de la API:

FamiliaNodePythonPHP.NET
Cobros (/v1/charges)client.chargesclient.charges$client->chargesclient.Charges
Operaciones de pago (/v1/payments)client.paymentsclient.payments$client->paymentsclient.Payments
Retiros (/v1/withdrawals)client.payoutsclient.payouts$client->payoutsclient.Payouts
Saldo (/v1/wallets)client.balanceclient.balance$client->balanceclient.Balance
Webhooks (/v1/webhooks)client.webhooks (incl. client.webhooks.endpoints)client.webhooks (incl. client.webhooks.endpoints)$client->webhooks (incl. $client->webhooks->endpoints)client.Webhooks (incl. client.Webhooks.Endpoints)
Casos MEDclient.medCasesclient.med_cases$client->medCasesclient.MedCases

Los nombres de los métodos siguen la convención de cada lenguaje (client.payments.create(input, { idempotencyKey }) en Node, client.payments.create(input, idempotency_key) en Python, $client->payments->create($input, $idempotencyKey) en PHP, client.Payments.CreateAsync(input, idempotencyKey) en .NET). payments.refund está ausente deliberadamente: la API responde 403 a toda solicitud con clave de API — error.code es "forbidden" y el mensaje comienza con el marcador REFUND_ADMIN_ONLY (un prefijo del mensaje, no un código), porque los reembolsos se realizan desde el panel de administración.

#Autenticación

text
Authorization: Bearer lq_live_…

Los SDKs envían el encabezado canónico Authorization: Bearer; la API sigue aceptando el encabezado heredado apikey: por compatibilidad. El entorno (test o live) se deriva de la propia clave. Nunca configuras un entorno, y nunca se envía ni se devuelve ningún identificador de cuenta o de comercio.

#La idempotencia es obligatoria en las escrituras financieras

Crear un cobro o un retiro requiere una clave de idempotencia. Los SDKs rechazan la llamada sin ella en lugar de enviarla y esperar que salga bien.

Deriva la clave de tu pedido (pedido-1234), nunca de un valor aleatorio. Un valor aleatorio anula todo el mecanismo: si tu solicitud llegó pero la respuesta se perdió, reintentar con una clave nueva crea un segundo cobro; reintentar con la misma clave devuelve el original.

#Política de reintentos

Situación¿Se reintenta?
GET / HEAD ante 5xx o error de redsí
POST con clave de idempotenciasí — la misma clave en cada intento
POST sin clave de idempotencianunca
Cualquier 4xxnunca — la solicitud es incorrecta, reintentar no la arreglará

El backoff es exponencial con jitter completo, con un máximo de 8s.

La tercera fila es la que importa. Un fallo de red no te dice si el servidor procesó la solicitud, solo que no llegó ninguna respuesta. Reintentar una escritura financiera sin clave ante esa ambigüedad es exactamente como a un cliente se le cobra dos veces.

#Inicio rápido

#Node.js

js
import { LiqfyClient } from '@liqfy/node';

const liqfy = new LiqfyClient({ apiKey: process.env.LIQFY_API_KEY });

const charge = await liqfy.charges.create(
  {
    amount: 15000,                 // R$ 150.00 in centavos — always an integer
    currency: 'BRL',
    payment_method: 'pix',
    customer: { name: 'Maria Silva', document: '12345678901' },
  },
  { idempotencyKey: `pedido-${orderId}` },
);

charge.pix.br_code;                // Pix Copia e Cola

#Python

python
import os
from liqfy import LiqfyClient

liqfy = LiqfyClient(api_key=os.environ["LIQFY_API_KEY"])

cobranca = liqfy.charges.create(
    {
        "amount": 15000,
        "currency": "BRL",
        "payment_method": "pix",
        "customer": {"name": "Maria Silva", "document": "12345678901"},
    },
    idempotency_key=f"pedido-{pedido_id}",
)

cobranca["pix"]["br_code"]

El SDK de Python no tiene dependencias en tiempo de ejecución: solo la biblioteca estándar. Un SDK de pagos se ejecuta dentro de tu proceso; cada paquete transitivo que incorpora se convierte en superficie de cadena de suministro que heredas de nosotros.

#PHP

php
<?php
require __DIR__ . '/vendor/autoload.php';

use Liqfy\LiqfyClient;

$cliente = new LiqfyClient(['apiKey' => getenv('LIQFY_API_KEY')]);

$cobranca = $cliente->charges->create([
    'amount' => 15000,
    'currency' => 'BRL',
    'payment_method' => 'pix',
    'customer' => ['name' => 'Maria Silva', 'document' => '12345678901'],
], 'pedido-' . $pedidoId);

$cobranca['pix']['br_code'];

#C#

csharp
using Liqfy;

// Register as a SINGLETON — it is thread-safe and reuses its HttpClient.
// One client per request exhausts TCP ports, the classic .NET trap.
var liqfy = new LiqfyClient(Environment.GetEnvironmentVariable("LIQFY_API_KEY")!);

var cobranca = await liqfy.Charges.CreateAsync(new
{
    amount = 15000,
    currency = "BRL",
    payment_method = "pix",
    customer = new { name = "Maria Silva", document = "12345678901" },
}, idempotencyKey: $"pedido-{orderId}");

var brCode = cobranca!.RootElement.GetProperty("pix").GetProperty("br_code").GetString();

#Verificación de webhooks

La verificación no necesita clave de API: instancia el helper de webhooks por sí solo.

js
// Node — Express with a raw body parser
app.post('/webhooks/liqfy', express.raw({ type: 'application/json' }), (req, res) => {
  if (!liqfy.webhooks.verify(req.body, req.headers['x-liqfy-signature'], secret)) {
    return res.status(401).end();
  }
  const event = JSON.parse(req.body.toString('utf8'));
  res.status(200).end();          // any 2xx confirms delivery
});
python
# Python — Flask
if not webhooks.verify(request.get_data(), request.headers.get("X-Liqfy-Signature"), secret):
    return "", 401
csharp
// C# — minimal API
if (!webhooks.Verify(corpo, req.Headers["X-Liqfy-Signature"], secret))
    return Results.Unauthorized();

Pasa los bytes sin procesar. No deserialices y vuelvas a serializar el cuerpo antes de verificarlo: cualquier diferencia en los espacios en blanco o en el orden de las claves cambia el HMAC y la firma falla. Este es el error de integración de webhooks más común, en todos los lenguajes.

Las firmas con más de 5 minutos de antigüedad se rechazan por defecto, lo que impide que un POST capturado se reproduzca indefinidamente. Consulta Webhooks para conocer el formato de la firma y el calendario de reintentos.

#Errores

Cada SDK lanza errores tipados que incluyen status, code, type y request_id.

Tipo de falloNodePythonPHPC#
401 / 403LiqfyAuthErrorLiqfyAuthErrorLiqfyAuthErrorLiqfyAuthException
400 / 422LiqfyValidationErrorLiqfyValidationErrorLiqfyValidationErrorLiqfyValidationException
409LiqfyConflictErrorLiqfyConflictErrorLiqfyConflictErrorLiqfyConflictException
Ninguna respuestaLiqfyNetworkErrorLiqfyNetworkErrorLiqfyNetworkErrorLiqfyNetworkException

Ramifica según code, nunca según el mensaje: los mensajes están escritos para personas y cambian sin previo aviso. code es contrato; consulta Errores para ver el catálogo. El único marcador de mensaje documentado es REFUND_ADMIN_ONLY (los reembolsos solo se realizan desde el panel de administración y responden un forbidden simple); compáralo como prefijo, no como código.

El error de red deliberadamente no es una subclase del error de la API en ninguno de los cuatro SDKs. Cuando no llega ninguna respuesta, no sabes si el servidor procesó la solicitud. Capturar ambos en una misma rama oculta precisamente la distinción que decide si reintentar es seguro.

Indica el request_id cuando contactes con soporte: permite localizar la solicitud exacta en nuestros registros.