@shieldz/sdk
    Preparing search index...

    @shieldz/sdk

    @shieldz/sdk

    npm CI types minzipped zero dependencies license

    Official Node / TypeScript SDK for Shieldz β€” non-custodial crypto payments with $0 fees.

    Accept USDC/USDT across Base, Arbitrum, Optimism, Polygon, and Ethereum, plus native Bitcoin and shielded Zcash. Funds settle straight to your own wallet β€” Shieldz never holds them, and never asks for your keys.

    • πŸͺͺ Non-custodial β€” payments go wallet β†’ wallet; you keep the keys.
    • πŸ’Έ $0 platform fees β€” you only pay network gas.
    • 🧩 Stripe-shaped API β€” create an invoice, send the hosted checkout, get a signed webhook.
    • 🌐 Runs anywhere β€” zero dependencies, pure web standards (fetch + Web Crypto). Works on Node 18+, Deno, Bun, Cloudflare Workers, and Vercel/Netlify Edge. Ships dual ESM + CommonJS (import and require).
    • πŸ” Resilient β€” automatic retries with backoff on transient failures, idempotent invoice creation, and async-iterator auto-pagination.
    npm install @shieldz/sdk
    

    Requires Node 18+ (or any runtime with fetch + Web Crypto). Get an API key (sk_live_… / sk_test_…) from your merchant dashboard β†’ Developers.

    import Shieldz from "@shieldz/sdk";

    const shieldz = new Shieldz(process.env.SHIELDZ_API_KEY!);

    // Create an invoice
    const invoice = await shieldz.invoices.create({
    amount_usd_cents: 5000, // $50.00
    memo: "Order #1234",
    metadata: { order_id: "1234" },
    });

    console.log(invoice.id, invoice.status, invoice.pay_url);
    // β†’ send your customer to invoice.pay_url (the hosted checkout)

    CommonJS works too:

    const { Shieldz } = require("@shieldz/sdk");
    const shieldz = new Shieldz(process.env.SHIELDZ_API_KEY);
    const inv = await shieldz.invoices.retrieve("Qgvz8WQw0mnv2M8");

    // One page
    const page = await shieldz.invoices.list({ limit: 20, status: "paid" });
    console.log(page.data, page.has_more);

    // …or auto-paginate across every page (follows the cursor for you)
    for await (const invoice of shieldz.invoices.listAll({ status: "paid" })) {
    console.log(invoice.id);
    }

    Sell from a catalog, the way Stripe does: prices live in Shieldz, so a buyer's browser can never change what they pay.

    const hoodie = await shieldz.products.create({
    name: "Blue hoodie",
    default_price_data: { unit_amount_usd_cents: 4999 },
    });

    // A hosted page (link.url) and the target of the widget's buy button:
    // <button data-shieldz-link="plink_…">Buy now</button>
    const link = await shieldz.paymentLinks.create({
    line_items: [{ product: hoodie.id, adjustable_quantity: { enabled: true, minimum: 1, maximum: 5 } }],
    collect_shipping_address: true,
    });

    // Or price an order on your server from line items:
    const invoice = await shieldz.invoices.create({
    line_items: [
    { price: hoodie.default_price!.id, quantity: 2 },
    { price_data: { name: "Gift wrap", unit_amount_usd_cents: 300 } },
    ],
    client_reference_id: "A-1043",
    });

    Paid invoices carry line_items, payment_link, client_reference_id and, when the link asked for it, shipping.

    Products and payment links have no test mode: a link takes real payments whichever key made it. To try a priced checkout without real money, create an invoice with line_items and an sk_test_ key. A checkout's total must be from $1 to $100,000. The full walkthrough is in examples/catalog.ts.

    Transient failures (network errors, timeouts, 429, and 5xx) are retried automatically with exponential backoff + jitter β€” 2 retries by default, honouring Retry-After. To make a retried POST /invoices safe, the SDK auto-attaches an idempotency_key, so a create can never duplicate. Pass your own idempotency_key to tie it to your order id:

    await shieldz.invoices.create({ amount_usd_cents: 5000, idempotency_key: "order_1234" });
    

    Replaying the same key returns the original invoice (idempotent_replay: true) instead of creating a second one. Tune or disable retries via maxRetries (see Configuration).

    Register an HTTPS endpoint in the dashboard and save the whsec_… signing secret. Shieldz sends invoice.paid and invoice.failed events, signed with HMAC-SHA256.

    Verification uses the Web Crypto API, so it's async and runs on any runtime (Node, Deno, Bun, Cloudflare Workers, Edge). Always verify against the raw request body (not a re-serialized object):

    import express from "express";
    import { constructEvent } from "@shieldz/sdk";

    const app = express();

    // Capture the raw body for this route
    app.post("/webhooks/shieldz", express.raw({ type: "application/json" }), async (req, res) => {
    try {
    const event = await constructEvent(
    req.body, // Buffer / Uint8Array (raw bytes)
    req.header("X-Shieldz-Signature") ?? "",
    process.env.SHIELDZ_WEBHOOK_SECRET!,
    );

    if (event.type === "invoice.paid") {
    // fulfill the order β€” idempotent on X-Shieldz-Delivery (deliveries are at-least-once)
    }
    res.sendStatus(200);
    } catch {
    res.sendStatus(400); // bad signature
    }
    });

    On Cloudflare Workers / Edge it's the same call β€” pass the raw body and header:

    export default {
    async fetch(req: Request, env): Promise<Response> {
    const raw = await req.text();
    try {
    const event = await constructEvent(raw, req.headers.get("X-Shieldz-Signature") ?? "", env.SHIELDZ_WEBHOOK_SECRET);
    // handle event…
    return new Response("ok");
    } catch {
    return new Response("bad signature", { status: 400 });
    }
    },
    };

    await verifySignature(rawBody, header, secret) is also exported if you just want a boolean check. During the 24h after a secret rotation, the header carries both signatures (v1=…,v1=…) and either matches.

    Any non-2xx response throws ShieldzError:

    import { ShieldzError } from "@shieldz/sdk";

    try {
    await shieldz.invoices.create({ amount_usd_cents: 1 }); // below the $1 minimum
    } catch (err) {
    if (err instanceof ShieldzError) {
    console.log(err.status, err.type, err.code, err.param, err.requestId);
    // 400 "invalid_request" "invalid_amount" "amount_usd_cents" "<cf-ray>"
    }
    }

    err.requestId is a correlation id for the failed request β€” quote it to support to trace it in the logs.

    const shieldz = new Shieldz({
    apiKey: "sk_live_…",
    baseUrl: "https://shieldz.cash/api/v1", // default
    timeoutMs: 30_000, // default per-request timeout
    maxRetries: 2, // default; set 0 to disable
    maxRetryDelayMs: 8_000, // cap on a single backoff delay
    fetch: globalThis.fetch, // inject a custom fetch if you like
    });

    Zero runtime dependencies, and every release is verifiable end-to-end:

    Socket Snyk OpenSSF Scorecard

    • npm provenance β€” published from CI with a Sigstore attestation (the "Provenance" badge on npm links the exact commit + workflow).
    • SBOM + checksums + signature β€” each GitHub Release ships a CycloneDX SBOM, SHASUMS256.txt, and a keyless cosign signature.
    • Scanned β€” CodeQL, OSV-Scanner, and OpenSSF Scorecard run in CI; dependencies tracked by Dependabot.
    • Inspect on deps.dev and ecosyste.ms.

    MIT Β© Deniz Yanbollu / Shieldz