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 🙏

© 2024 – Pkg Stats / Ryan Hefner

paddle-billing

v3.1.0

Published

Paddle Billing API and Webhooks wrapper with detailed TypeScript types

Downloads

497

Readme

Paddle Billing

Paddle Billing API, Webhooks and web (Paddle.js) wrapper with detailed TypeScript types.

Installing

The library is available as an npm package.

To install the package run:

npm install paddle-billing

The minimum required Node.js version is v18, as it uses Fetch API. It's possible to use older versions with global.fetch polyfill, but not recommended.

Usage

API

paddle-billing wraps all available Paddle Billing API methods, replicating the naming structure. Every API component (query, body, response, etc) is carefully typed, so you can use those as the documentation or read the Paddle API Reference for more details.

To use a method, create a client with authentication details and call the method with it:

import { client, cancelSubscription } from "paddle-billing";

const paddle = client("PADDLE_SECRET");

cancelSubscription(paddle, "SUBCRIPTION_ID").then((subscription) => {
  if (subsription.error) {
    // The request failed:
    console.error(subscription.error); // See PaddleAPI.Error
    return;
  }

  // Do something with the subscription:
  subscription.data;
});

Sandbox

To use the Sandbox, pass true as the second argument to client:

import { client, cancelSubscription } from "paddle-billing";

const paddle = client("PADDLE_SECRET", true);

// Will send the request to Sandbox:
cancelSubscription(paddle, "SUBCRIPTION_ID");

Typing custom_data

To add types to custom_data fields to Price, Product, SubscriptionItem, Subscription, Transaction, Customer, Address and Business add the generic argument to client:

const paddle = client<{
  Product: CustomDataProduct;
  Price: CustomDataPrice;
  Transaction: CustomDataTransaction;
  Subscription: CustomDataSubscription;
  SubscriptionItem: CustomDataSubscriptionItem;
  Customer: CustomDataCustomer;
  Address: CustomDataAddress;
  Business: CustomDataBusiness;
}>("PADDLE_SECRET");

From now on, all corresponding entities will have custom_data typed.

⚠️ When specifing Subscription and Transaction, you should make sure they overlap. Fields that do not overlap should be optional. It's dictated by the web's custom data-assigning to relevant transaction and subscription simultaneously. Creating an API or web client with incompatible custom data definitions will result in the client function returning never.

All custom data fields are optional so that you can type only selected entities:

const paddle = client<{
  Product: CustomDataProduct;
  Price: CustomDataPrice;
}>("PADDLE_SECRET");

Key function

You can also pass a function that returns the key as the key argument, which allows the use of Google Cloud Secrets and calling client on the module level where the secrets aren't defined in process:

const paddle = client(() => "PADDLE_SECRET");

Methods List

Webhooks

To verify and parse the Paddle webhook, use parseWebhookBody function:

import express from "express";
import { parseWebhookBody } from "paddle-billing/webhooks";

const app = express();

app.use(express.raw());

// Use the webhook's secret that you get when creating it the Paddle admin:
const secret = process.env.PADDLE_WEBHOOK_SECRET;

app.get("/paddle-webhook", (request, response) => {
  // Extract the webhook signature from the headers
  const signature = request.headers["paddle-signature"];
  if (!signature) {
    response.status(400).send("Bad Request");
    return;
  }

  // Parse the webhook
  const webhook = parseWebhookBody(
    null,
    secret,
    signature,
    // ⚠️ the body must be raw string to parse!
    request.body.toString()
  );

  // If the webhook is invalid, it will be null
  if (!webhook) {
    response.status(400).send("Bad Request");
    return;
  }

  response.send("OK");
});

If you have custom data types defined, pass the client as the first argument so that the custom data is correctly inferred:

const paddle = client<{
  Product: CustomDataProduct;
  Price: CustomDataPrice;
  Transaction: CustomDataTransaction;
  Subscription: CustomDataSubscription;
  SubscriptionItem: CustomDataSubscriptionItem;
  Customer: CustomDataCustomer;
  Address: CustomDataAddress;
  Business: CustomDataBusiness;
}>("PADDLE_SECRET");

// ...later:

const webhook = parseWebhookBody(
  paddle,
  secret,
  signature,
  request.body.toString()
);

Web

The package also provides the web portion of the Paddle Billing platform replacing the first-party package @paddle/paddle-js. Unlike the official package, this one provides more elaborate types and integration with custom data that you might use on the backend.

To load the web API (known as Paddle.js), use loadScript:

import { loadScript } from "paddle-billing/web";

loadScript().then((Paddle) => {
  Paddle.Checkout.open({
    settings: {
      displayMode: "overlay",
      theme: "light",
      locale: "en",
    },

    items: [
      {
        priceId: "pri_01gm81eqze2vmmvhpjg13bfeqg",
        quantity: 1,
      },
      {
        priceId: "pri_01gm82kny0ad1tk358gxmsq87m",
        quantity: 1,
      },
    ],
  });
});

If you have custom data assigned to Paddle entities, use the loadScript generic param, the same way as when creating the API client:

interface CustomData {
  Transaction: AccountData;
  Subscription: AccountData;
}

interface AccountData {
  accountId: string;
}

const paddle = client<CustomData>("PADDLE_SECRET");

// ...later on web:

loadScript<CustomData>().then((Paddle) => {
  Paddle.Checkout.open({
    items: [
      {
        priceId: "pri_01gm81eqze2vmmvhpjg13bfeqg",
        quantity: 1,
      },
    ],

    customData: {
      accountId: "ACCOUNT_ID",
    },
  });
});

⚠️ When specifing Subscription and Transaction, you should make sure they overlap. Fields that do not overlap should be optional. It's dictated by the web's custom data-assigning to relevant transaction and subscription simultaneously. Creating an API or web client with incompatible custom data definitions will result in the client function returning never.

Read more about using custom data through API.

License

MIT © Sasha Koss