npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@liquidafy/liquidafy-js

v1.1.0

Published

Official Liquidafy SDK for Node.js — crypto-native checkout for LATAM (USDT charges, withdrawals, refunds, webhooks).

Downloads

443

Readme

Liquidafy SDK — JavaScript/TypeScript

CI npm version License: MIT

Official, hand-crafted SDK for Node.js. npm: @liquidafy/liquidafy-js.

Liquidafy — crypto-native checkout gateway for LATAM. Accept USDT, pay out in fiat, refund customers — one REST API.

Install

npm install @liquidafy/liquidafy-js
# or
pnpm add @liquidafy/liquidafy-js

Requirements: Node.js >= 18 (native fetch). Zero runtime dependencies. TypeScript types included.

⚠️ NEVER use your secret key in the browser

lr_live_* and lr_test_* are secret keys. Anyone who reads them in your page source can move your funds. This SDK is server-side only in 1.x and throws immediately if instantiated in a browser.

For browser checkout, create the charge on your server and redirect the buyer to the hosted pay-page (charge.checkout_url).

A browser bundle with publishable keys (lr_pk_*) and an embeddable checkout component is planned for a future release — it is intentionally not part of this package today.

Quickstart

1. Create a charge (server-side)

import { randomUUID } from 'node:crypto';
import { Liquidafy } from '@liquidafy/liquidafy-js';

const liquidafy = new Liquidafy(process.env.LIQUIDAFY_API_KEY!); // lr_test_... or lr_live_...

const charge = await liquidafy.charges.create(
  {
    amount: '100.00',           // amounts are ALWAYS decimal strings — never floats
    currency: 'USDT',
    description: 'Pedido #1234',
    customer: { email: '[email protected]' },
    metadata: { order_id: '1234' },
  },
  { idempotencyKey: randomUUID() }, // makes retries safe; the SDK warns if omitted
);

// Redirect the buyer to the hosted pay-page:
console.log(charge.checkout_url);

2. Verify a webhook (Express)

The signature covers the raw body bytes — use express.raw, never express.json, on the webhook route.

import express from 'express';
import { Liquidafy, LiquidafySignatureError } from '@liquidafy/liquidafy-js';

const liquidafy = new Liquidafy(process.env.LIQUIDAFY_API_KEY!);
const app = express();

app.post(
  '/webhooks/liquidafy',
  express.raw({ type: 'application/json' }), // ← raw body, REQUIRED
  (req, res) => {
    try {
      const event = liquidafy.webhooks.constructEvent(
        req.body,                                  // raw Buffer
        req.headers['liquidafy-signature'] as string,
        process.env.LIQUIDAFY_WEBHOOK_SECRET!,     // shown once at endpoint creation
        300,                                       // tolerance in seconds (default 300)
      );

      switch (event.type) {
        case 'charge.confirmed':
          // fulfill the order — event.data.object is the Charge
          break;
        case 'withdrawal.confirmed':
          break;
      }
      res.status(200).send('OK');
    } catch (err) {
      if (err instanceof LiquidafySignatureError) {
        return res.status(400).send('Invalid signature');
      }
      throw err;
    }
  },
);

constructEvent verifies the Liquidafy-Signature header (t=<unix>,v1=<hex(hmac-sha256(secret, "<t>.<body>"))>) with a constant-time comparison and rejects timestamps outside the tolerance window (replay protection). It works in any handler that gives you the raw body (Next.js route handlers, Fastify with rawBody, Cloudflare Workers with nodejs_compat, ...).

3. Auto-pagination

// Lazy async iterator — fetches pages on demand, cancelable via break:
for await (const charge of liquidafy.charges.list({ status: 'confirmed' }).autoPaginate()) {
  console.log(charge.id, charge.amount);
}

// Or eagerly (careful with huge lists):
const all = await liquidafy.withdrawals.list({ type: 'crypto' }).autoPaginate().toArray();

// Manual cursor:
const page1 = await liquidafy.charges.list({ limit: 50 });
const page2 = await liquidafy.charges.list({ limit: 50, cursor: page1.next_cursor! });

Resources

| Resource | Methods | |---|---| | liquidafy.charges | create, retrieve, list, cancel, refund | | liquidafy.refunds | create(chargeId, ...), retrieve, list | | liquidafy.withdrawals | create (crypto/fiat), retrieve, list, cancel | | liquidafy.webhookEndpoints | create, retrieve, list, update, del, rotateSecret, disable, enable, listDeliveries, test | | liquidafy.fx | quote, retrieveQuote, rates | | liquidafy.merchants | me, update, balance, getSettings, updateSettings | | liquidafy.test | simulateDeposit (sandbox only — requires lr_test_*) | | liquidafy.webhooks | constructEvent |

Client options

const liquidafy = new Liquidafy('lr_test_...', {
  apiVersion: '2026-05-01',                 // pin the API shape
  baseURL: 'https://api.sandbox.liquidafy.com',
  maxRetries: 3,                            // network/5xx/429 only — never other 4xx
  timeout: 30_000,                          // ms
  appInfo: { name: 'MeuApp', version: '1.2.3', url: 'https://meuapp.com' },
  telemetry: true,                          // runtime info in User-Agent
});

Retries & idempotency

Failed requests are retried up to 3 times with exponential backoff (1s/2s/4s ± 25% jitter) on network errors, 5xx, and 429 (honoring Retry-After). Other 4xx are never retried.

Mutations (POST/PATCH) are only retried when you pass { idempotencyKey } — the SDK refuses to blind-retry a request it cannot prove idempotent, and logs a console.warn to remind you.

Errors

import {
  LiquidafyAPIError,
  LiquidafyAuthenticationError,
  LiquidafyRateLimitError,
  LiquidafyValidationError,
} from '@liquidafy/liquidafy-js';

try {
  await liquidafy.charges.create({ amount: '10.00', currency: 'USDT' }, { idempotencyKey: key });
} catch (err) {
  if (err instanceof LiquidafyRateLimitError) {
    console.log('retry in', err.retryAfterMs);
  } else if (err instanceof LiquidafyValidationError) {
    console.log(err.code, err.details);
  } else if (err instanceof LiquidafyAPIError) {
    console.log(err.statusCode, err.code, err.requestId);
  } else {
    throw err;
  }
}

Every API error exposes statusCode, code (stable, switchable), requestId, details and headers. API keys are always masked (lr_live_***1234) and never logged.

Sandbox helpers

const liquidafy = new Liquidafy('lr_test_...');

await liquidafy.test.simulateDeposit({
  to_address: charge.deposit_address,
  amount: '100.000000',
  confirmations: 19, // ≥19 lands the deposit at `confirmed`
});

Calling test.simulateDeposit with a live key throws locally (and is rejected server-side).

Development

pnpm install
pnpm lint             # tsc --noEmit (strict)
pnpm test             # vitest
pnpm build            # tsup → dist (ESM + CJS + d.ts)

src/types/api.ts is generated from the Liquidafy OpenAPI specification (pnpm generate:types, maintainers only — expects an openapi.yaml in the repo root, which is not committed). Don't hand-edit generated files.

Security

Found a vulnerability? Never open a public issue. Report it privately to [email protected] or via GitHub private vulnerability reporting — see SECURITY.md for scope, supported versions, and response times.

License

MIT © Liquidafy Labs Ltda

Contact