Getting started
Install
npm install @klappay/node@klappay/types comes along as a dependency automatically — you don't need to install it separately just to use the SDK.
Create a client
import { createClient } from '@klappay/node'
const klap = createClient({
baseUrl: 'https://your-klap-api-host',
apiKey: process.env.KLAP_API_KEY,
})baseUrl has no hardcoded default on purpose — there's no single API host every integration would want, and a wrong silent default is a much harder bug to notice than one that fails loudly. It still has to come from somewhere, though: pass it explicitly (shown above), or set KLAP_BASE_URL and drop the option entirely — createClient() falls back to it.
apiKey is a klap_live_.../klap_test_... key — it's required for every method on the client (charges, webhooks, sandbox, distributions, networks, metrics, recipients). The example above reads it from process.env manually, which still works, but is now redundant — createClient() already falls back to KLAP_API_KEY on its own, so createClient({ baseUrl: '...' }) alone is enough once that variable is set.
Optional: debug: true (logs every outgoing request's method + URL — never the Authorization header — to help diagnose what the SDK is actually sending), and timeoutMs (aborts a request after this long; default 30s — a hung API or dropped connection would otherwise hang your code forever. The waitFor*() methods use their own AbortSignal/timeout logic and aren't affected by this option).
const klap = createClient({
baseUrl: 'https://your-klap-api-host',
apiKey: process.env.KLAP_API_KEY,
debug: true, // logs "POST https://your-klap-api-host/v1/charges" etc.
timeoutMs: 10_000, // abort any request that hangs past 10s
})apiKey can also change after construction, without building a new client — klap.setApiKey().
Environment variables
Every create*Client() — including the standalone ones documented in tree-shaking.md — falls back to process.env when baseUrl/apiKey are omitted, so a fully env-configured project never has to pass either:
import { createRecipientsClient } from '@klappay/node/recipients'
const recipients = createRecipientsClient() // reads KLAP_BASE_URL + KLAP_RECIPIENTS_API_KEYKLAP_BASE_URL is shared by every client — one Klap API host per process. apiKey is scoped per resource instead, since recipients/ charges/metrics/etc. keys carry different permissions and are deliberately never the same key (see recipients.md's scope-separation section):
| Client | Env var |
|---|---|
createClient() | KLAP_API_KEY |
createChargesClient() | KLAP_CHARGES_API_KEY |
createWebhooksClient() | KLAP_WEBHOOKS_API_KEY |
createMetricsClient() | KLAP_METRICS_API_KEY |
createSandboxClient() | KLAP_SANDBOX_API_KEY |
createDistributionsClient() | KLAP_DISTRIBUTIONS_API_KEY |
createNetworksClient() | KLAP_NETWORKS_API_KEY |
createRecipientsClient() | KLAP_RECIPIENTS_API_KEY |
An explicit apiKey/baseUrl argument always wins over its env var. Going through the composed createClient(), KLAP_API_KEY (if set) is used for every resource uniformly — the resource-specific vars only kick in when going through a standalone create*Client() directly, or when createClient() has no apiKey option and KLAP_API_KEY isn't set either. If nothing resolves at all, the first call that needs it throws MissingBaseUrlError/MissingCredentialError — same as passing neither today, just discovered at the first request instead of at construction for baseUrl.
Your first charge
const charge = await klap.charges.create({
amount: 49.9,
acceptedPayments: [{ token: 'USDC', network: 'base' }],
expiresIn: 3600,
})
console.log(charge.id, charge.address, charge.status) // 'pending'charge here isn't just plain data — it's a live object with methods attached (refresh(), waitForConfirmation(), waitForSettlement()). See charges.md for the full resource reference, including what those methods actually do and how they resolve/reject.
Where to go next
charges.md— the core resource: create, list, paginate, and (the SDK's main value-add) observe a charge's status until it resolves.webhooks.md— registering webhooks, and verifying signatures on what you receive.recipients.md— registering trusted split recipients, and referencing them byrecipientIdin a charge split.metrics.md— ad-hoc analytics over your charges/ transactions/distributions data.distributions.md— discovering and streaming claimable 0xSplits payouts, for keepers/bots, not a typical merchant integration.networks.md— the live(token, network)capability matrix, for building a payment-method picker instead of hardcoding it.sandbox-testing.md— testing your integration end-to-end without any real on-chain activity.errors.md— every error class the SDK throws, and when.tree-shaking.md— importing only what you use, for bundle-size-sensitive environments (e.g. serverless cold starts).
For LLMs and agents
This site (built from these same files with VitePress) publishes llms.txt — a link index of every doc page — and llms-full.txt — the full content of every doc page concatenated into one plain-text file. Point an agent, RAG pipeline, or MCP server at either as a lightweight way to give it the whole SDK's documentation without scraping HTML. Both regenerate on every deploy, so they never drift from what's on this page.
