For AI agents and LLMs: a structured documentation index is available at /llms.txt. Every page has a Markdown sibling — append .md to any URL.

Skip to content
Docs

Libraries

Official Paddle server-side SDKs for Node.js, Python, Go, and PHP, plus the Paddle.js wrapper for client-side JavaScript and TypeScript.

AI summary

Use Paddle's official server-side SDKs for Node.js, Python, Go, and PHP, plus the typed Paddle.js wrapper for client-side JavaScript and TypeScript. All server SDKs share patterns for authentication, pagination, error handling, and webhook signature verification.

  • • Each SDK takes an environment-specific API key — using a sandbox key against the live API (or vice versa) returns forbidden.
  • • Failed requests throw typed errors with an errorCode; 400 validation errors include field-level details; Paddle doesn't support idempotency keys, so verify before retrying.
  • • Every SDK includes a webhook verifier for the Paddle-Signature header; SDKs follow semver, so keep them updated as the API evolves.

Paddle publishes official SDKs for Node.js, Python, Go, and PHP, plus a typed ES-module wrapper for Paddle.js. Each SDK is hand-written, kept in lockstep with the API, and distributed on the package registry for its language.

Server-side SDKs

Client-side

For the untyped <script> tag version of Paddle.js, see Include and initialize Paddle.js.

Common patterns

Some behavior is the same across every server-side SDK.

Authentication

Each SDK takes an API key and an environment. API keys and client-side tokens are environment-specific: use a sandbox credential for sandbox, a live credential for production. Cross-environment credentials return a forbidden error.

Node.js
import { Paddle, Environment } from '@paddle/paddle-node-sdk';
const paddle = new Paddle(process.env.PADDLE_API_KEY!, {
environment: Environment.sandbox,
});
Python
from os import getenv
from paddle_billing import Client, Environment, Options
paddle = Client(
getenv('PADDLE_API_KEY'),
options=Options(Environment.SANDBOX),
)
Go
import (
"os"
paddle "github.com/PaddleHQ/paddle-go-sdk/v5"
)
client, err := paddle.New(
os.Getenv("PADDLE_API_KEY"),
paddle.WithBaseURL(paddle.SandboxBaseURL),
)
PHP
use Paddle\SDK\Client;
use Paddle\SDK\Environment;
use Paddle\SDK\Options;
$paddle = new Client(
apiKey: getenv('PADDLE_API_KEY'),
options: new Options(Environment::SANDBOX),
);

Pagination

List endpoints return collections that can be iterated across pages. Each SDK exposes pagination idiomatically for its language: async iterators in Node.js, plain iterators in Python and PHP, and an Iter callback in Go.

Node.js
const products = paddle.products.list();
for await (const product of products) {
console.log(product.id, product.name);
}
// Or page explicitly using `.next()` and `.hasMore`.
Python
for product in paddle.products.list():
print(product.id, product.name)
Go
products, err := client.ListProducts(ctx, &paddle.ListProductsRequest{})
if err != nil {
return err
}
err = products.Iter(ctx, func(p *paddle.Product) (bool, error) {
fmt.Println(p.ID, p.Name)
return true, nil
})
PHP
foreach ($paddle->products->list() as $product) {
echo $product->id . ' ' . $product->name . PHP_EOL;
}

Error handling

Failed API calls raise a typed error with an errorCode matching the error reference. Validation errors include a list of field-level details. Rate-limit responses (too_many_requests) include a retry-after hint.

Node.js
import { ApiError } from '@paddle/paddle-node-sdk';
try {
await paddle.products.create({ name: 'Starter', taxCategory: 'standard' });
} catch (e) {
const err = e as ApiError;
if (err.code === 'conflict') {
// Handle a conflict, e.g. duplicate resource.
}
throw e;
}
Python
from paddle_billing.Exceptions.ApiError import ApiError
try:
paddle.products.create(...)
except ApiError as error:
if error.error_code == 'conflict':
# Handle a conflict.
pass
raise
Go
import (
"errors"
paddle "github.com/PaddleHQ/paddle-go-sdk/v5"
)
_, err := client.CreateProduct(ctx, &paddle.CreateProductRequest{
Name: "Starter",
})
var apiErr *paddle.APIError
if errors.As(err, &apiErr) && apiErr.Code == "conflict" {
// Handle a conflict.
}
PHP
use Paddle\SDK\Exceptions\ApiError;
try {
$paddle->products->create($operation);
} catch (ApiError $e) {
if ($e->errorCode === 'conflict') {
// Handle a conflict.
}
throw $e;
}

Look up a specific error code in the error reference for cause and remediation.

Webhook signature verification

Every SDK ships with a webhook signature verifier that checks the Paddle-Signature header using your notification destination's secret key. See respond to webhooks for how signatures work and how to configure a destination.

Node.js
import { Paddle, EventName } from '@paddle/paddle-node-sdk';
const paddle = new Paddle(process.env.PADDLE_API_KEY!);
const event = paddle.webhooks.unmarshal(
requestBody,
process.env.PADDLE_WEBHOOK_SECRET!,
signatureHeader,
);
Python
from paddle_billing.Notifications import Secret, Verifier
integrity = Verifier().verify(request, Secret(PADDLE_WEBHOOK_SECRET))
Go
verifier := paddle.NewWebhookVerifier(os.Getenv("PADDLE_WEBHOOK_SECRET"))
handler := verifier.Middleware(yourHandler)
PHP
use Paddle\SDK\Notifications\Secret;
use Paddle\SDK\Notifications\Verifier;
(new Verifier())->verify($request, new Secret(getenv('PADDLE_WEBHOOK_SECRET')));

Idempotent and retried requests

The Paddle API doesn't currently support client-supplied idempotency keys for arbitrary operations.

If an SDK call times out or fails with a network error, retry carefully. A create operation may have succeeded even if your process didn't receive the response. Before retrying a create, list or get the entity to check whether it already exists.

Versioning

SDKs follow semantic versioning. Breaking changes result in a new major version.

Languages have different conventions around what's considered a breaking change. A non-breaking change to the Paddle API, like adding optional fields or enum values, doesn't necessarily mean an SDK won't require a major version bump.

Keep your SDK version up to date so types and runtime behavior stay aligned with the latest API.

Was this page helpful?