Kaskade Pay Docs
API Reference · v1

Kaskade Pay API

The Kaskade Pay API lets you accept and send cryptocurrency from your own app or backend. Price in USD, let customers pay in 300+ coins, reconcile with signed webhooks, and pay out to external wallets — all behind one stable, JSON-over-HTTPS contract.

Availability tags. Each endpoint is marked Live (callable today),Beta (live, may still change), or Planned (contract published, backend rollout in progress). Build against any of them — the shapes are committed.

Infrastructure & stability

Kaskade Pay is a contract-first API. The endpoints, fields and webhook events on this page are the product — the settlement engine behind them is an implementation detail that you never touch. Your keys are Kaskade Pay keys, your objects are Kaskade Pay objects, and your webhooks are signed with your Kaskade Pay secret.

That separation is deliberate. Today settlement runs on a third-party custody provider; as volume grows we move to self-custody on an MPC platform (e.g. Fireblocks-class infrastructure) with our own on-chain wallets, treasury and payout signing. None of that changes a single request you make.The base URL, authentication, payment object, statuses and webhook payloads are guaranteed stable across that migration.

What is guaranteed stable
FieldTypeRequiredDescription
Base URL & versionrequiredhttps://kaskade.com/api/v1 stays; breaking changes only ever ship under a new version prefix.
AuthenticationrequiredBearer keys and HMAC signing are unaffected by backend changes.
Object shapesrequiredExisting fields are never removed or repurposed; we only add new optional fields.
Webhook eventsrequiredEvent names, payload shape and signature scheme stay constant.
StatusesrequiredThe payment status vocabulary is fixed (new states, if any, are additive).
Bottom line: integrate once. When we swap or in-source the crypto infrastructure, your code keeps working with no migration on your side.

Base URL & environments

All endpoints are served over HTTPS from one versioned base URL. Plain HTTP is rejected.

Base URL
https://kaskade.com/api/v1
Conventions
FieldTypeRequiredDescription
Content-TypeheaderrequiredAll request and response bodies are application/json.
AmountsnumberoptionalFiat amounts are decimal USD. Crypto amounts are decimal in the coin's own unit.
TimestampsstringoptionalISO-8601 in UTC, e.g. 2026-06-20T12:34:56.000Z.
IDsstringoptionalOpaque strings — never parse or assume a format.

Versioning & changelog

The current version is v1, pinned in the URL path. We treat the following as backward-compatible and may ship them without a version bump:

  • Adding new endpoints, optional request fields, or response fields.
  • Adding new webhook event types or new enum values.
  • Changing an endpoint's availability tag from Planned → Beta → Live.

Anything breaking (removing a field, changing a type) would only ship under a new prefix such as /api/v2, and v1 would keep running. Material changes are listed in the dashboard changelog.

Quick start

  1. Create an API key. In your dashboard, open Developers and create a key. Copy the secret — shown only once.
  2. Create a payment. POST a USD price and the coin to pay in; you get a deposit address and the exact crypto amount.
  3. Collect payment. Show the address (or our hosted page) to your customer.
  4. Fulfil on webhook. Act when you receive a payment.updated event with status finished.
curl -X POST https://kaskade.com/api/v1/payments \
  -H "Authorization: Bearer ks_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "priceUsd": 50,
    "payCurrency": "btc",
    "orderId": "ORDER-123",
    "orderDescription": "Premium plan"
  }'

Authentication

Every request must be authenticated. Two schemes grant the same access — use whichever fits your stack.

  • Bearer key — simplest; send your secret key in a header.
  • Request signing (HMAC) — strongest; sign each request so the key is never transmitted.

Bearer keys

Pass your key (ks_live_…) in the Authorization header. x-api-key: ks_live_… is also accepted.

Header
Authorization: Bearer ks_live_xxx
Keep keys server-side. A live key can move money — never ship it in a browser, mobile app or public repo. Revoking and rotating are instant in the dashboard.

Request signing (HMAC)

Sign each request with your key's client secret; the secret never leaves your server. Enable a signing secret on any key in the dashboard — your Client ID is the key's Public ID.

Headers
FieldTypeRequiredDescription
X-Pharosgate-ClientstringrequiredYour Client ID (the key's Public ID).
X-Pharosgate-TimestampstringrequiredISO-8601 UTC time, within 5 minutes of server time (replay protection).
X-Pharosgate-SignaturestringrequiredBase64 HMAC-SHA256 of the canonical string, keyed with your client secret.

Build the canonical string by concatenating six parts in order, with no separators:

canonical =
BOM + METHOD + fullURL + clientId + timestamp + rawBody
Parts
FieldTypeRequiredDescription
BOMconstantrequiredThe Unicode byte-order mark .
METHODstringrequiredUpper-case HTTP method, e.g. POST.
fullURLstringrequiredFull request URL as called, e.g. https://kaskade.com/api/v1/payments.
clientIdstringrequiredSame as the X-Pharosgate-Client header.
timestampstringrequiredSame as the X-Pharosgate-Timestamp header.
rawBodystringrequiredExact JSON body; empty string "" for GET.
import crypto from "crypto";

const clientId     = "YOUR_CLIENT_ID";   // = your key's Public ID
const clientSecret = "pg_sk_xxx";         // shown once when you enable signing

const method = "POST";
const url    = "https://kaskade.com/api/v1/payments";        // the full URL, exactly as called
const ts     = new Date().toISOString();
const body   = JSON.stringify({ priceUsd: 50, payCurrency: "btc", orderId: "ORDER-123" });

// canonical = BOM + METHOD + URL + clientId + timestamp + body
const canonical = "\ufeff" + method + url + clientId + ts + body;
const signature = crypto.createHmac("sha256", clientSecret)
  .update(canonical, "utf8").digest("base64");

const res = await fetch(url, {
  method,
  headers: {
    "Content-Type": "application/json",
    "X-Pharosgate-Client": clientId,
    "X-Pharosgate-Timestamp": ts,
    "X-Pharosgate-Signature": signature,
  },
  body,
});

Errors & status codes

Conventional HTTP status codes; errors carry a human-readable error message.

Error response
{ "error": "priceUsd (number) and payCurrency (string) are required" }
CodeMeaning
200OK.
400Bad request — invalid params or below the coin's minimum.
401Unauthorized — missing, invalid, or unsigned credentials.
404Not found — resource doesn't exist or isn't yours.
409Conflict — idempotency key reused with a different body.
429Too many requests — slow down (see rate limits).
500Server error.
502Upstream settlement error — safe to retry.

Idempotency Planned

To safely retry POST requests without creating duplicates, send an Idempotency-Key header with a unique value (e.g. a UUID) per logical operation. We store the first response for 24 hours and replay it for any retry with the same key.

Header
Idempotency-Key: 9f1c8a3e-1b2d-4c5f-8a90-abc123def456

Reusing a key with a different body returns 409 Conflict. Until this ships, dedupe on your side using orderId (we surface it on the payment).

Pagination

List endpoints return the most recent items (currently up to 100, newest first). Cursor pagination via limit and starting_after is the committed contract and rolls out with the same response envelope:

Planned envelope
{
  "data": [ /* … items … */ ],
  "has_more": true,
  "next_cursor": "cmq7c0aa0000abc"
}

Today, list responses return a plain array under a resource key (e.g. payments). The cursor envelope is additive and tagged Planned.

Rate limits

Limits protect the platform and are applied per API key. When exceeded you receive 429 Too Many Requests; back off and retry with jitter.

Response headers
FieldTypeRequiredDescription
X-RateLimit-LimitintoptionalRequests allowed in the current window.
X-RateLimit-RemainingintoptionalRequests left in the window.
Retry-AfterintoptionalSeconds to wait before retrying (on 429).

Generous defaults suit normal checkout traffic. Need a higher limit for batch jobs? Talk to us.

Currencies

Prices are set in USD and converted at a live rate. Customers can pay in 300+ coins and tokens across major networks. Pass a coin's ticker as payCurrency when creating a payment; network-specific tickers select the chain.

btcethusdterc20usdttrc20usdcbnbbscsolltcxrptondogematic

List currencies

GET/currenciesLive

Returns the coins your account can accept, with display name and network. For a coin's live minimum payable amount, call Get a currency.

curl https://kaskade.com/api/v1/currencies \
  -H "Authorization: Bearer ks_live_xxx"
Response
{
  "currencies": [
    { "code": "btc",       "name": "Bitcoin",         "network": "bitcoin", "enabled": true },
    { "code": "usdttrc20", "name": "Tether (TRC-20)", "network": "tron",    "enabled": true }
  ]
}

Get a currency

GET/currencies/:codeLive

Metadata for a single coin, including the current minimum payable amount in USD (the same minimum enforced by Create a payment).

curl https://kaskade.com/api/v1/currencies/btc \
  -H "Authorization: Bearer ks_live_xxx"
Response
{
  "currency": { "code": "btc", "name": "Bitcoin", "network": "bitcoin", "minUsd": 18.92, "enabled": true }
}

Rates

Get a live conversion estimate before creating a payment — useful to preview the crypto amount a customer will owe for a given USD price.

Estimate a rate

GET/rates/estimateLive

Quotes how much of currency equals a given USD amount at the current rate.

Query parameters
FieldTypeRequiredDescription
amountnumberrequiredUSD amount to convert.
currencystringrequiredTarget coin ticker (e.g. btc).
curl https://kaskade.com/api/v1/rates/estimate?amount=50&currency=btc \
  -H "Authorization: Bearer ks_live_xxx"
Response
{
  "amountUsd": 50,
  "currency": "btc",
  "estimatedAmount": 0.00052471,
  "rate": 95291.41
}

Fees

Kaskade Pay charges a transparent percentage on successful payments. Your effective rate and fee mode (absorb vs. add-on) are configured per account in the dashboard.

Get fees

GET/feesLive

Returns the fee schedule that applies to your account.

curl https://kaskade.com/api/v1/fees \
  -H "Authorization: Bearer ks_live_xxx"
Response
{
  "platformFeePercent": 1.5,
  "merchantExtraPercent": 0,
  "feeMode": "absorb",
  "currency": "USD"
}

The payment object

A payment is a single request for funds — created in USD, paid in crypto.

FieldTypeRequiredDescription
idstringoptionalKaskade Pay payment id — use it to look the payment up later.
statusstringoptionalCurrent state. See statuses.
priceUsdnumberoptionalAmount charged, in USD.
payCurrencystringoptionalCoin the customer pays in.
payAmountnumberoptionalExact crypto amount due.
payAddressstringoptionalDeposit address to show the customer.
payInHashstring | nulloptionalOn-chain deposit transaction hash, once detected.
actuallyPaidnumberoptionalAmount received so far (handles underpayment).
orderIdstring | nulloptionalYour reference, echoed back.
expiresAtstring | nulloptionalWhen the quote/address expires.
createdAtstringoptionalISO-8601 creation time.

Payment statuses

StatusMeaning
waitingCreated; awaiting the customer's funds.
confirmingDeposit seen on-chain; awaiting confirmations.
confirmedConfirmed on-chain; settling.
sendingFunds routing to settlement.
partially_paidUnderpaid; remainder still pending.
finishedSettled. Fulfil the order here.
failedPayment failed.
refundedPayment refunded.
expiredNo funds before the quote expired.

Create a payment

POST/paymentsLive

Creates a payment priced in USD and returns a deposit address and the exact crypto amount.

Body parameters
FieldTypeRequiredDescription
priceUsdnumberrequiredUSD amount to charge. Must meet the coin's minimum.
payCurrencystringrequiredCoin to pay in (btc, eth, usdttrc20, usdc…).
orderIdstringoptionalYour order reference (≤ 200 chars). Echoed back and in webhooks.
orderDescriptionstringoptionalHuman-readable description (≤ 500 chars).
curl -X POST https://kaskade.com/api/v1/payments \
  -H "Authorization: Bearer ks_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "priceUsd": 50,
    "payCurrency": "btc",
    "orderId": "ORDER-123",
    "orderDescription": "Premium plan"
  }'
Response
{
  "payment": {
    "id": "cmq7c1ab0000xyz",
    "npPaymentId": "4912345678",
    "priceUsd": 50,
    "payCurrency": "btc",
    "payAmount": 0.00052471,
    "payAddress": "bc1qexampleaddressxxxxxxxxxxxxxxxxxxxx",
    "status": "waiting",
    "expiresAt": "2026-06-20T12:34:56.000Z"
  }
}

List payments

GET/paymentsLive

Returns your most recent payments (up to 100), newest first.

curl https://kaskade.com/api/v1/payments \
  -H "Authorization: Bearer ks_live_xxx"
Response
{
  "payments": [
    { "id": "cmq7c1ab0000xyz", "status": "finished", "priceAmount": 50, "payCurrency": "btc", "payInHash": "f4a1…", "createdAt": "2026-06-20T12:00:00.000Z" },
    { "id": "cmq7c0aa0000abc", "status": "waiting",  "priceAmount": 25, "payCurrency": "usdttrc20", "createdAt": "2026-06-20T11:40:00.000Z" }
  ]
}

Retrieve a payment

GET/payments/:idLive

Fetches one payment by id and refreshes its status live before returning, so it always reflects the latest on-chain state.

Path parameters
FieldTypeRequiredDescription
idstringrequiredThe payment id from Create a payment.
curl https://kaskade.com/api/v1/payments/cmq7c1ab0000xyz \
  -H "Authorization: Bearer ks_live_xxx"
Response
{
  "payment": {
    "id": "cmq7c1ab0000xyz",
    "status": "finished",
    "priceAmount": 50,
    "payCurrency": "btc",
    "payAmount": 0.00052471,
    "actuallyPaid": 0.00052471,
    "payAddress": "bc1qexampleaddressxxxxxxxxxxxxxxxxxxxx",
    "payInHash": "f4a1c9b2…",
    "createdAt": "2026-06-20T12:00:00.000Z"
  }
}

The invoice object Live

An invoice is a hosted, shareable request for payment. It produces a checkout URL your customer opens to pay in any supported coin, and emits the same payment.updated webhooks under the hood.

FieldTypeRequiredDescription
idstringoptionalInvoice id.
statusstringoptionaldraft | open | paid | expired | void.
amountUsdnumberoptionalAmount requested, in USD.
urlstringoptionalHosted checkout URL to share with the customer.
orderIdstring | nulloptionalYour reference.
customerEmailstring | nulloptionalOptional; receipt is emailed here.
paymentIdstring | nulloptionalLinked payment once the customer pays.
expiresAtstring | nulloptionalWhen the invoice expires.
createdAtstringoptionalISO-8601 creation time.

Create an invoice

POST/invoicesLive

Creates a hosted invoice and returns a shareable checkout URL.

Body parameters
FieldTypeRequiredDescription
amountUsdnumberrequiredUSD amount to request.
orderIdstringoptionalYour order reference.
orderDescriptionstringoptionalShown on the checkout page.
customerEmailstringoptionalEmails a receipt and reminders.
payCurrencystringoptionalLock to one coin; omit to let the customer choose.
curl -X POST https://kaskade.com/api/v1/invoices \
  -H "Authorization: Bearer ks_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "amountUsd": 120, "orderId": "INV-2026-014", "customerEmail": "buyer@example.com" }'
Response
{
  "invoice": {
    "id": "inv_8f2a1c",
    "status": "open",
    "amountUsd": 120,
    "url": "https://kaskade.com/i/8f2a1c",
    "orderId": "INV-2026-014",
    "customerEmail": "buyer@example.com",
    "expiresAt": "2026-06-21T12:00:00.000Z",
    "createdAt": "2026-06-20T12:00:00.000Z"
  }
}

List invoices

GET/invoicesLive

Returns your invoices, newest first.

curl https://kaskade.com/api/v1/invoices \
  -H "Authorization: Bearer ks_live_xxx"

Retrieve an invoice

GET/invoices/:idLive

Fetch one invoice; its status reconciles from the linked payment before returning.

curl https://kaskade.com/api/v1/invoices/inv_8f2a1c \
  -H "Authorization: Bearer ks_live_xxx"

Get balances

GET/balanceLive

Returns your available balance per coin.

curl https://kaskade.com/api/v1/balance \
  -H "Authorization: Bearer ks_live_xxx"
Response
{
  "balances": {
    "btc": 0.01340000,
    "usdttrc20": 250.50
  }
}

Wallet addresses Planned

POST/wallets/addressesPlanned
Planned endpoint. Generates a dedicated deposit address you can attribute to a customer or account — the building block for per-user wallets in self-custody mode. The request/response shape below is the committed contract — build against it now and it will work unchanged when the endpoint goes live. See Infrastructure & stability.
Body parameters
FieldTypeRequiredDescription
currencystringrequiredCoin/network for the address.
labelstringoptionalYour reference for attribution (e.g. user id).
curl -X POST https://kaskade.com/api/v1/wallets/addresses \
  -H "Authorization: Bearer ks_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{ "currency": "usdttrc20", "label": "user_4821" }'
Response
{
  "address": {
    "id": "addr_19be4",
    "currency": "usdttrc20",
    "address": "TXexampleaddressxxxxxxxxxxxxxxxxxxx",
    "label": "user_4821",
    "createdAt": "2026-06-20T12:00:00.000Z"
  }
}

The payout object Planned

A payout sends crypto from your balance to an external wallet. In self-custody mode these are signed by Kaskade Pay's own treasury; under thresholds they auto-sign, above them they await approval.

FieldTypeRequiredDescription
idstringoptionalPayout id.
statusstringoptionalpending | approved | sent | failed.
currencystringoptionalCoin/network sent.
amountnumberoptionalCrypto amount sent.
addressstringoptionalDestination wallet address.
txHashstring | nulloptionalOn-chain transaction hash once broadcast.
orderIdstring | nulloptionalYour reference.
createdAtstringoptionalISO-8601 creation time.

Create a payout

POST/payoutsPlanned
Planned endpoint. Requests a withdrawal to an external address. Idempotency is strongly recommended here. The request/response shape below is the committed contract — build against it now and it will work unchanged when the endpoint goes live. See Infrastructure & stability.
Body parameters
FieldTypeRequiredDescription
currencystringrequiredCoin/network to send.
amountnumberrequiredCrypto amount to send.
addressstringrequiredDestination wallet address.
orderIdstringoptionalYour reference for reconciliation.
curl -X POST https://kaskade.com/api/v1/payouts \
  -H "Authorization: Bearer ks_live_xxx" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 9f1c8a3e-1b2d-4c5f-8a90-abc123def456" \
  -d '{ "currency": "usdttrc20", "amount": 100, "address": "TXdest…", "orderId": "WD-771" }'
Response
{
  "payout": {
    "id": "po_5c1a9d",
    "status": "pending",
    "currency": "usdttrc20",
    "amount": 100,
    "address": "TXdest…",
    "orderId": "WD-771",
    "createdAt": "2026-06-20T12:00:00.000Z"
  }
}

List payouts

GET/payoutsPlanned
Planned endpoint. Returns your payouts, newest first. The request/response shape below is the committed contract — build against it now and it will work unchanged when the endpoint goes live. See Infrastructure & stability.
curl https://kaskade.com/api/v1/payouts \
  -H "Authorization: Bearer ks_live_xxx"

Webhooks

Set a webhook URL in your dashboard; we POST an event every time a payment changes status. This is the reliable way to know when to fulfil — never rely on the customer's browser returning.

POST to your URL
{
  "event": "payment.updated",
  "payment": {
    "id": "cmq7c1ab0000xyz",
    "status": "finished",
    "orderId": "ORDER-123",
    "priceAmount": 50,
    "payCurrency": "btc",
    "payInHash": "f4a1c9b2…"
  }
}

Event types

EventWhen
payment.updatedA payment changes status (incl. finished).Live
invoice.paidA hosted invoice is fully paid.Live
payout.updatedA payout changes status (sent/failed).Planned

All events share the same envelope (event + resource object) and the same signature scheme, so one handler covers them all.

Verifying signatures

Each delivery carries an x-kaskade-signature header — HMAC-SHA256 (hex) of the raw request body, keyed with your webhook signing secret. Always verify before trusting the event.

import crypto from "crypto";

// Express raw-body handler for POST /webhooks/kaskade
app.post("/webhooks/kaskade", (req, res) => {
  const signature = req.headers["x-kaskade-signature"];
  const expected = crypto
    .createHmac("sha256", process.env.KASKADE_WEBHOOK_SECRET)
    .update(req.rawBody)            // the exact bytes we sent
    .digest("hex");

  if (signature !== expected) return res.status(401).end();

  const { event, payment } = JSON.parse(req.rawBody);
  if (payment.status === "finished") {
    // ✅ fulfil the order (idempotently)
  }
  res.status(200).end();
});

Delivery & retries

Respond 2xx quickly. Failed deliveries retry automatically with backoff, and you can re-send any delivery from the dashboard. Events are de-duplicated per status — make your handler idempotent (e.g. key off payment.id + status).

Official SDKs Planned

Thin, typed clients that wrap auth (including request signing) and every endpoint on this page. Until they ship, the code examples below are copy-paste ready in any language — the API is plain HTTPS + JSON.

Planned packages
FieldTypeRequiredDescription
Node.jsnpmoptionalnpm i @kaskade/sdk
PHPcomposeroptionalcomposer require kaskade/sdk
Pythonpipoptionalpip install kaskade

Postman collection

Import the collection to call every endpoint with your key pre-wired. It includes a baseUrl variable and an apiKey variable — set them once and go.

Download collection (.json)

In Postman: Import → Upload Files → select the file, then set the collection variables baseUrl and apiKey.

Code examples

Create a payment

curl -X POST https://kaskade.com/api/v1/payments \
  -H "Authorization: Bearer ks_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{
    "priceUsd": 50,
    "payCurrency": "btc",
    "orderId": "ORDER-123",
    "orderDescription": "Premium plan"
  }'

Authenticate with request signing

import crypto from "crypto";

const clientId     = "YOUR_CLIENT_ID";   // = your key's Public ID
const clientSecret = "pg_sk_xxx";         // shown once when you enable signing

const method = "POST";
const url    = "https://kaskade.com/api/v1/payments";        // the full URL, exactly as called
const ts     = new Date().toISOString();
const body   = JSON.stringify({ priceUsd: 50, payCurrency: "btc", orderId: "ORDER-123" });

// canonical = BOM + METHOD + URL + clientId + timestamp + body
const canonical = "\ufeff" + method + url + clientId + ts + body;
const signature = crypto.createHmac("sha256", clientSecret)
  .update(canonical, "utf8").digest("base64");

const res = await fetch(url, {
  method,
  headers: {
    "Content-Type": "application/json",
    "X-Pharosgate-Client": clientId,
    "X-Pharosgate-Timestamp": ts,
    "X-Pharosgate-Signature": signature,
  },
  body,
});

Verify a webhook

import crypto from "crypto";

// Express raw-body handler for POST /webhooks/kaskade
app.post("/webhooks/kaskade", (req, res) => {
  const signature = req.headers["x-kaskade-signature"];
  const expected = crypto
    .createHmac("sha256", process.env.KASKADE_WEBHOOK_SECRET)
    .update(req.rawBody)            // the exact bytes we sent
    .digest("hex");

  if (signature !== expected) return res.status(401).end();

  const { event, payment } = JSON.parse(req.rawBody);
  if (payment.status === "finished") {
    // ✅ fulfil the order (idempotently)
  }
  res.status(200).end();
});

Integration options

There's more than one way to accept crypto with Kaskade Pay — from sharing a link in seconds to wiring the full API into your platform. Pick the lightest option that meets your need; you can mix them, and they all settle to the same account and emit the same webhooks.

OptionBest forEffort
Hosted invoiceOne-off bills, freelancers, "send me a payment link"No code
Payment links & buttonsA fixed-price product or donate/checkout button on any siteCopy-paste
POS terminalTaking crypto in person at a counterNo code
DonationsTips, fundraising, "pay what you want"No code
SubscriptionsRecurring/membership billingLow code
REST API + webhooksCustom checkout, marketplaces, full controlDeveloper
Platform pluginsWooCommerce, WHMCS and other off-the-shelf storesInstall
Not sure? If you run a store on a known platform, start with a plugin. If you bill people directly, use a hosted invoice. If you're building your own product, go straight to the API.

Plugins & platforms

Drop-in plugins let popular platforms accept crypto through Kaskade Pay without custom code. Packaged plugins are rolling out; in the meantime every platform below can be wired up in minutes with the Create a payment endpoint and a webhook.

WooCommerce Planned

For WordPress + WooCommerce stores. The official gateway plugin (Planned) adds "Pay with crypto" at checkout, redirects the shopper to a hosted invoice, and marks the order paid on the invoice.paid webhook. Until it ships, integrate with a few lines in your theme or a small custom gateway:

  1. Create an API key and set it in your server config (never in client JS).
  2. On order placement, call POST /invoices with the order total as amountUsd and the WooCommerce order id as orderId.
  3. Redirect the customer to the returned invoice url.
  4. On the invoice.paid webhook (verify the signature), mark the matching order complete.

WHMCS Planned

For hosting and SaaS billing on WHMCS. The official payment-gateway module (Planned) registers Kaskade Pay as a gateway so invoices can be paid in crypto and auto-reconciled. Manual integration mirrors WooCommerce: create a Kaskade Pay invoice from the WHMCS invoice, send the client to the hosted checkout, and apply the payment when invoice.paid arrives (map by orderId = WHMCS invoice id).

Want early access to a plugin? Tell us your platform from the dashboard and we'll prioritise it. The integration recipe above keeps you live today regardless.

Team & multi-user access

Most teams need more than one person — or service — touching the gateway. Here's how access works today and what's coming.

API keys as machine identities Live

Create a separate API key for each app, environment or service that talks to Kaskade Pay. Keys are independent — name them ("production server", "staging", "billing worker"), rotate or revoke any one instantly without affecting the others, and enable request signing per key. This is the practical way to give each part of your stack its own credential and audit trail.

Team seats & roles Planned

Inviting teammates to the dashboard with roles — owner, admin, developer(keys & webhooks), and viewer (read-only reporting) — is on the roadmap. The committed model: one account owns the merchant, members are invited by email, and each role scopes what they can see and do. Until then, keep the account owner's login limited and use per-service API keys for automation.

Best practice. One key per service, least privilege, rotate on staff changes, and never share a single key across environments — so revoking one never takes down everything.

Export transaction history

Pull your payments for bookkeeping, reconciliation or accounting in two ways.

From the dashboard (CSV) Live

Open Payment history and click Export CSV to download your full payment history as a spreadsheet-ready file. Columns:

FieldTypeRequiredDescription
idstringoptionalKaskade Pay payment id.
created_atstringoptionalISO-8601 creation time (UTC).
statusstringoptionalFinal or current status.
price_usdnumberoptionalAmount charged in USD.
pay_currencystringoptionalCoin paid.
pay_amountnumberoptionalCrypto amount due.
actually_paidnumberoptionalCrypto amount received.
order_idstringoptionalYour order reference.
deposit_tx_hashstringoptionalOn-chain deposit TXID, if any.
provider_payment_idstringoptionalInternal settlement reference.

Via the API Live

For automated exports or syncing to your own ledger, page through List paymentsand persist what you need. Combine with webhooks to keep your records live instead of polling.

curl https://kaskade.com/api/v1/payments \
  -H "Authorization: Bearer ks_live_xxx"

Migrating & support

Already integrated with another crypto gateway? Kaskade Pay maps cleanly: a “create charge” becomes Create a payment, IPNs become webhooks, and your order reference rides along as orderId. Because the contract is provider-agnostic (see why), you integrate once and never re-migrate.

Stuck on something? Open a ticket from your dashboard or contact support.

FAQ

Do I need a separate key for signing?

No. Every API key can use Bearer auth, and you can additionally enable a signing secret on the same key.

What happens to my integration when you change crypto infrastructure?

Nothing. The contract on this page is stable across backend changes — see Infrastructure & stability.

How do I test without real money?

Create a small live payment (e.g. $5+) and pay it on-chain, or reach out for sandbox access.

Which status means “paid”?

finished. Fulfil orders on that webhook, idempotently.