Embedded Checkout
Embedded Checkout — methods, parameters, and examples for @easylabs/node.
Embedded checkout creates a server-side session that the browser opens in an iframe. The session carries a one-time client_secret so the iframe-side validation and confirmation calls can be authorized without your secret API key.
@easylabs/node is a server-side SDK — createClient({ apiKey }) validates a secret API key, so the package itself must never be loaded in a browser bundle. Two of the methods on this resource — validateEmbeddedCheckoutSession and confirmEmbeddedCheckoutSession — still authenticate with the session's client_secret rather than the API key (the SDK suppresses the API-key header for those two requests), but you call them from your own server endpoints, which the iframe reaches via your own fetch. If you'd rather hit POST /embedded-checkout/validate and POST /embedded-checkout/confirm directly from the browser with the client_secret, that's also supported — just don't reach for the Node SDK to do it.
Methods
createEmbeddedCheckoutSession(data)
POST /embedded-checkout. Returns ApiResponse<EmbeddedCheckoutSessionData>.
const { data: session } = await easy.createEmbeddedCheckoutSession({
line_items: [{ price_id: "PR_...", quantity: 1 }],
mode: "payment", // or "subscription"
return_url: "https://app.example.com/checkout/return",
success_url: "https://app.example.com/checkout/success",
cancel_url: "https://app.example.com/checkout/cancel",
customer_email: "ada@example.com",
payment_methods: ["card"], // include "crypto" to accept Solana Pay
metadata: { cart_id: "cart_42" },
});
// Hand session.client_secret to the iframe; render session.url.getEmbeddedCheckoutSession(sessionId)
GET /embedded-checkout/:id. Returns EmbeddedCheckoutSessionStatus — status ("open" | "complete" | "expired"), payment_status, amount_total, line_items, customer_email, metadata, created_at, completed_at.
getCryptoPaymentStatus(sessionId)
GET /embedded-checkout/:id/crypto-status. Poll for the on-chain confirmation when payment_methods includes "crypto".
validateEmbeddedCheckoutSession(body) (server-side, client-secret authed)
POST /embedded-checkout/validate. Lives on the server-side client returned by createClient, but authenticates with the session's client_secret rather than the API key — the SDK suppresses the x-easy-api-key header for this single call. Rate-limited (~30 req/min per session). Returns the resolved session config — branding, line items, allowed origins. Expose this through your own server endpoint that the iframe calls.
confirmEmbeddedCheckoutSession(body) (server-side, client-secret authed)
POST /embedded-checkout/confirm. Same auth model as validateEmbeddedCheckoutSession: server-side method, client_secret-authed, API-key header suppressed. Submits the tokenized payment source and finalizes the session.
getEmbeddedCheckoutConfig()
GET /embedded-checkout/config. Server-only. Returns the company's allowed-origins config.
updateEmbeddedCheckoutConfig(body)
PATCH /embedded-checkout/config. Pass { allowed_origins: ["https://app.example.com", "https://*.example.com"] }. An empty array disables embedding entirely.
Object shape
EmbeddedCheckoutSessionData (returned by create):
| Field | Type | Notes |
|---|---|---|
id | string | Session ID. |
client_secret | string | One-time secret for the browser. Do not log. |
url | string | URL to embed in the iframe. |
amount_total | number | Smallest currency unit. |
currency | string | |
status | string | Initial status. |
expires_at | string | ISO timestamp. |
crypto_payment | CryptoPaymentInfo | undefined | Present when payment_methods includes "crypto". |
EmbeddedCheckoutConfig: id, company_id, allowed_origins: string[], created_at, updated_at.
Examples
Create + render
// app/api/checkout/route.ts
export async function POST(req: Request) {
const { priceId } = await req.json();
const { data } = await easy.createEmbeddedCheckoutSession({
line_items: [{ price_id: priceId, quantity: 1 }],
mode: "payment",
return_url: "https://app.example.com/checkout/return",
});
return Response.json({ clientSecret: data.client_secret, url: data.url });
}Authorize an embedding origin
await easy.updateEmbeddedCheckoutConfig({
allowed_origins: [
"https://app.example.com",
"https://*.example.com", // wildcard subdomains
],
});Poll a crypto session
async function awaitCryptoConfirmation(sessionId: string, deadlineMs: number) {
while (Date.now() < deadlineMs) {
const { data } = await easy.getCryptoPaymentStatus(sessionId);
if (data.status === "confirmed") return data;
if (data.status === "failed" || data.status === "expired") throw new Error(data.status);
await new Promise((r) => setTimeout(r, 3000));
}
throw new Error("timeout");
}