← Files WixARCHIVED FILE

skills/wix-headless-templates/donations/rest/donate.ts

3.11 KB · Oct 8, 2026 · 12:02 UTC

↓ Download file

See the change to this file →

// The donation flow over REST — the twin of app/wix/donations/donate.ts. Same exports, same
// signatures; the bodies and result readers come from donations-core (the SAME file the SDK
// transport uses). A donation is an eCom cart with one catalog line; the hosted checkout takes
// payment and donor details. In Cart V2 the cart IS the checkout — its id is the id the redirect
// session takes, so there is one route and no separate Create Checkout call. Never create the
// order yourself, never hand-build a checkout URL.
// docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/cart-v2/create-cart.md
// docs: https://dev.wix.com/docs/api-reference/business-management/headless/redirects/create-redirect-session.md
// docs: https://dev.wix.com/docs/api-reference/business-solutions/e-commerce/purchase-flow/orders/get-order.md
import { wixRequest } from "./client.js";
import {
  cartBody,
  cartIdOf,
  checkoutError,
  redirectBody,
  redirectUrl,
  toReceipt,
  type DonatePaths,
  type Raw,
} from "./donations-core.js";
import type { DonationInput, DonationReceipt } from "./types.js";

export type { DonatePaths };

export interface DonateOptions {
  /** The site's public https origin (default: window.location.origin — call from the browser). */
  origin?: string;
  /** Where the hosted checkout returns to; a static site passes its file paths. */
  paths?: DonatePaths;
}

/**
 * Start the hosted checkout for a donation; resolves to the URL to navigate the FULL document to.
 * `origin` must be the site's real https origin as registered on the OAuth app's allowed domains.
 * POST /ecom/v2/carts  { cart: { source: { channelType: "WEB" }, note? }, catalogItems: [{ quantity: 1, catalogReference: { appId, catalogItemId, options: { amount, frequency, donorCoveringFees? } } }] }  → { cart: { id } } (the cart is the checkout)
 * POST /headless/v1/redirect-session  { ecomCheckout: { checkoutId }, callbacks: { postFlowUrl, thankYouPageUrl } }  → { redirectSession: { fullUrl } }
 */
export async function donationCheckoutUrl(campaignId: string, input: DonationInput, { origin, paths }: DonateOptions = {}): Promise<string> {
  const site = origin ?? (typeof window !== "undefined" ? window.location.origin : "");
  let cartId: string;
  try {
    const res = await wixRequest<Raw>("/ecom/v2/carts", { body: cartBody(campaignId, input) });
    cartId = cartIdOf(res);
  } catch (e) {
    throw checkoutError(e);
  }
  const session = await wixRequest<Raw>("/headless/v1/redirect-session", { body: redirectBody(cartId, campaignId, site, paths) });
  return redirectUrl(session);
}

/**
 * The order behind a completed donation, for the thank-you page; null on any failure (the order may
 * not be readable with the visitor's token — thank without order facts then).
 * GET /ecom/v1/orders/{id}  → { order }
 */
export async function fetchDonationReceipt(orderId: string): Promise<DonationReceipt | null> {
  if (!orderId) return null;
  try {
    const res = await wixRequest<Raw>(`/ecom/v1/orders/${orderId}`, { method: "GET" });
    return res?.order ? toReceipt(res.order) : null;
  } catch {
    return null;
  }
}

SHA-256: 7b0f3a89c22d4b17f187b343495d0fae8558b508738cabc8a679989ae8dbb978