Skip to content

Getting started

Install

bash
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

ts
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).

ts
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:

ts
import { createRecipientsClient } from '@klappay/node/recipients'

const recipients = createRecipientsClient() // reads KLAP_BASE_URL + KLAP_RECIPIENTS_API_KEY

KLAP_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):

ClientEnv 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

ts
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 by recipientId in 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.

Docs live in ./docs — the source of truth for both the package and this site.