Getting started
Accept Curvy checkout payments from a Node backend in a few steps.
Installation
Install the Payments SDK on the server. Payment request creation needs the Rust WASM peer on that same package:
pnpm add @0xcurvy/payments-sdk @0xcurvy/[email protected]npm install @0xcurvy/payments-sdk @0xcurvy/[email protected]yarn add @0xcurvy/payments-sdk @0xcurvy/[email protected]Node.js 22.16 or newer is required. Browser-only packages that only verify signed requests or scan receipts can omit @0xcurvy/rs-core-wasm and skip the /merchant entry point.
Do not install @0xcurvy/curvy-sdk for merchant checkout. That package is the privacy wallet.
1. Initialize the SDK
Use only public receiving keys on the server (S, V, BabyJubjub). Keep spending and viewing keys offline.
Bind SDK-wide settings once — recipient, chain, origin, confirmations, and request TTL:
import { initialize } from "@0xcurvy/payments-sdk/merchant";
const sdk = initialize({
recipient: {
S: process.env.CURVY_PUBLIC_S!,
V: process.env.CURVY_PUBLIC_V!,
babyJubjubPublicKey: process.env.CURVY_PUBLIC_BABYJUBJUB!,
},
chainId,
merchantOrigin: "https://shop.example",
confirmations: 12,
ttlSeconds: 600, // optional; defaults to 10 minutes
// optional: checkoutCompletePath: "/orders/paid",
});Create the client once at process startup and reuse it for every checkout.
2. Create a payment request
For each checkout, pass only amount and token:
const request = await sdk.createPaymentRequest({
amount: 10_000_000n, // token base units
token: usdcAddress,
});Each request includes a fresh payment reference (ephemeralKeyX, ephemeralKeyY). Store these values — you need them later to call verifyPayment.
Omitted checkoutCompletePath defaults to /checkout/complete and is always included in the EIP-712 typed data.
For one-off or advanced use, the standalone createPaymentRequest({ recipient, amount, token, chainId, merchantOrigin, ... }) export remains available on /merchant.
3. Sign and build the checkout URL
import { signPaymentIntent } from "@0xcurvy/payments-sdk/intent";
import { buildCheckoutUrl } from "@0xcurvy/payments-sdk/transport";
const payment = await signPaymentIntent(request, (typedData) =>
merchantSigner.signTypedData(typedData),
);
const checkoutUrl = buildCheckoutUrl(CURVY_CHECKOUT_ORIGIN, payment);Redirect the customer to checkoutUrl. The signed package travels in the URL fragment, not the query string.
4. Publish your signers
Serve GET https://shop.example/.well-known/curvy-payments.json with CORS so Curvy checkout can verify the signature before showing a pay UI. See Human checkout.
5. Confirm on-chain
Call sdk.verifyPayment with the stored payment reference (ephemeralKeyX, ephemeralKeyY). When checkout returns #txHash=…, pass that hash as well — it speeds up confirmation by checking the shield transaction directly. If you do not have a hash yet, omit txHash and the SDK queries on-chain logs for batch commitment of that payment reference. Retry on your own schedule until the call returns true. See Confirming payments.
Next steps
- Human checkout integration
- API surface
- Wallet SDK if you are building a private-balance app instead of a shop