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

@bloque/payments

v0.2.1

Published

Official Bloque SDK for creating and managing payments and checkouts.

Readme

Bloque Payments SDK

Official TypeScript/JavaScript SDK for integrating Bloque payments.

Installation

bun add @bloque/payments

Authentication

The SDK supports a three-credential model:

| Credential | Prefix | Where | Purpose | |------------|--------|-------|---------| | Secret key | sk_test_ / sk_live_ | Server only | Exchanged for a short-lived JWT via /origins/api-keys/exchange | | Publishable key | pk_test_ / pk_live_ | Browser | Identifies the merchant; read-only (view cart) | | Client secret | JWT | Browser | Scoped JWT for a single checkout session (checkout.pay) |

Initialize (recommended)

import { Bloque } from '@bloque/payments';

const bloque = new Bloque({
  mode: 'sandbox',
  secretKey: process.env.BLOQUE_SECRET_KEY!,
  webhookSecret: process.env.BLOQUE_WEBHOOK_SECRET, // optional
});

The SDK automatically exchanges the secret key for a JWT and caches it (with refresh 1 min before expiry).

Initialize (legacy)

const bloque = new Bloque({
  mode: 'sandbox',
  accessToken: process.env.BLOQUE_ACCESS_TOKEN!, // deprecated — use secretKey
});

Quick Start: Create Checkout

import { Bloque } from '@bloque/payments';

const bloque = new Bloque({
  mode: 'sandbox',
  secretKey: process.env.BLOQUE_SECRET_KEY!,
});

const checkout = await bloque.checkout.create({
  name: 'Pack Profesional de Productividad',
  description:
    'Periféricos premium para trabajo intensivo y alto rendimiento',
  asset: 'COPM/2',
  image_url: 'https://cdn.bloque.app/checkouts/productivity-pack.png',
  items: [
    {
      name: 'Teclado mecánico Keychron K2',
      description: 'Wireless, RGB, switches Blue',
      amount: 450_000_00,
      quantity: 2,
      image_url: 'https://cdn.bloque.app/items/keychron-k2.png',
    },
    {
      name: 'Mouse Logitech MX Master 3S',
      description: 'Inalámbrico, sensor 8K DPI',
      amount: 380_000_00,
      quantity: 1,
      image_url: 'https://cdn.bloque.app/items/mx-master-3s.png',
    },
  ],
  success_url: 'https://bloque.app/success',
  cancel_url: 'https://bloque.app/cancel',
  merchant: {
    name: 'Bloque',
    theme: {
      primary: '#10b981',
      primary_foreground: '#ffffff',
      background: '#f8fafc',
      surface: '#ffffff',
      border: '#d1d5db',
      input_border: '#10b98166',
    },
  },
  payment_methods: ['card', 'pse', 'cash'],
  payeer: {
    name: 'Nestor Cortina',
    email: '[email protected]',
  },
});

console.log('Checkout URL:', checkout.url);

API

Bloque config

type BloqueConfig = {
  mode: 'sandbox' | 'production';
  secretKey: string;        // sk_test_... or sk_live_...
  timeout?: number;         // request timeout in ms (default 10_000)
  maxRetries?: number;      // retry count (default 2)
  webhookSecret?: string;
};

/** @deprecated Use BloqueConfig with secretKey instead */
type BloqueConfigLegacy = {
  mode: 'sandbox' | 'production';
  accessToken: string;
  timeout?: number;
  maxRetries?: number;
  webhookSecret?: string;
};

Checkout

bloque.checkout.create(params)

type CheckoutParams = {
  name: string;
  description?: string;
  image_url?: string;
  asset?: 'COPM/2' | 'DUSD/6';
  items: {
    name: string;
    description?: string;
    amount: number;
    quantity: number;
    image_url?: string;
  }[];
  success_url: string;
  cancel_url: string;
  metadata?: Record<string, string | number | boolean>;
  merchant?: {
    name: string;
    theme: {
      primary: string;
      primary_foreground: string;
      background: string;
      surface: string;
      border: string;
      input_border: string;
    };
  };
  payment_methods?: ('card' | 'pse' | 'cash')[];
  expires_at?: string;
};

Notes:

  • asset defaults to DUSD/6 when omitted.
  • Creation request is sent using redirect_url derived from success_url.

Response shape:

type Checkout = {
  id: string;
  urn: string;
  object: 'checkout';
  url: string;
  client_secret: string;   // scoped JWT for browser-side checkout
  status: 'pending' | 'paid' | 'expired' | 'deposited' | 'cancelled';
  amount_total: number;
  amount_subtotal: number;
  asset: 'COPM/2' | 'DUSD/6';
  items: {
    name: string;
    description?: string;
    amount: number;
    quantity: number;
    image_url?: string;
  }[];
  metadata?: Record<string, string | number | boolean>;
  created_at: string;
  updated_at: string;
  expires_at: string | null;
};

Pass the client_secret to @bloque/payments-core or @bloque/payments-react on the browser to authorize payment execution.

bloque.checkout.retrieve(checkoutId)

const checkout = await bloque.checkout.retrieve('checkout_123');

bloque.checkout.cancel(checkoutId)

const checkout = await bloque.checkout.cancel('checkout_123');

Payments

bloque.payments.create(params)

Supported direct payment methods are card, pse, and cash (maps to POST /payments/:type on the server).

const payment = await bloque.payments.create({
  paymentUrn: 'did:bloque:payments:123e4567-e89b-12d3-a456-426614174000',
  payment: {
    type: 'card',
    data: {
      cardNumber: '4111111111111111',
      cardholderName: 'John Doe',
      expiryMonth: '12',
      expiryYear: '2028',
      cvv: '123',
      email: '[email protected]',
      installments: 1,
      currency: 'COP',
    },
  },
});

Payment response:

type PaymentResponse = {
  id: string;
  object: 'payment';
  status: 'approved' | 'rejected' | 'pending';
  amount: number;
  currency: string;
  created_at: string;
  three_ds?: { current_step: string; iframe: string };
};

bloque.payments.getStatus(paymentId)

Poll payment status by URN (e.g. did:bloque:payments:...) after a 3DS challenge.

const latest = await bloque.payments.getStatus(payment.id);

3D Secure (direct API)

When you process card payments server-side with 3DS, pass browser fingerprint fields and optional sandbox scenario:

import type { BrowserInfo } from '@bloque/payments';

function browserInfoFromRequest(req: {
  headers: Record<string, string | string[] | undefined>;
}): BrowserInfo {
  const ua = String(req.headers['user-agent'] ?? '');
  const accept = String(req.headers['accept'] ?? '*/*');
  const lang = String(req.headers['accept-language'] ?? 'en');
  return {
    browser_user_agent: ua,
    browser_language: lang,
    browser_color_depth: '24',
    browser_screen_height: '900',
    browser_screen_width: '1440',
    browser_tz: '0',
  };
}

const payment = await bloque.payments.create({
  checkoutId: 'checkout_123',
  payment: {
    type: 'card',
    data: {
      cardNumber: '4111111111111111',
      cardholderName: 'John Doe',
      expiryMonth: '12',
      expiryYear: '2028',
      cvv: '123',
      email: '[email protected]',
      is_three_ds: true,
      browser_info: browserInfoFromRequest(req),
      three_ds_auth_type: 'challenge_v2', // sandbox only; omit in production
    },
  },
});

if (payment.three_ds?.iframe) {
  // 1) Decode HTML entities if the gateway returns escaped HTML
  // 2) If iframe is a URL (https://...), use <iframe src="...">
  // 3) Otherwise use <iframe srcdoc={decodedHtml}> with sandbox allow-scripts allow-forms allow-popups
  // 4) Show Mastercard ID Check branding before/around the challenge where required
  // 5) Poll until terminal state:
  let status = payment.status;
  while (status === 'pending') {
    await new Promise((r) => setTimeout(r, 3000));
    const next = await bloque.payments.getStatus(payment.id);
    status = next.status;
  }
}

Field names for BrowserInfo match the Bloque Payments API (browser_user_agent, browser_language, etc.).

Webhooks

Verify webhook signature (HMAC-SHA256):

const isValid = bloque.webhooks.verify(
  rawBody,
  signature,
  { secret: process.env.BLOQUE_WEBHOOK_SECRET! },
);

You can also set webhookSecret during Bloque initialization and omit options in verify.

Example

Full example available at:

  • examples/basic-checkout.ts