Easy Labs
SDKsNode.jsResources

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 EmbeddedCheckoutSessionStatusstatus ("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):

FieldTypeNotes
idstringSession ID.
client_secretstringOne-time secret for the browser. Do not log.
urlstringURL to embed in the iframe.
amount_totalnumberSmallest currency unit.
currencystring
statusstringInitial status.
expires_atstringISO timestamp.
crypto_paymentCryptoPaymentInfo | undefinedPresent 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");
}

On this page