TypeScript client

For a developer who would rather not hand-roll fetch calls. @cascade-commerce/api is a typed client for both Cascade APIs, generated from the same OpenAPI documents this reference is built from, so it never drifts from what the API actually accepts.

You do not need it. Every endpoint is an ordinary HTTPS request and the reference gives you curl for each one. The client is there so your editor knows the shapes.

Install

npm install @cascade-commerce/api

There are two entry points, one per API:

Entry pointAPICredential
@cascade-commerce/api/adminThe admin API, called from your backend.Secret key, as a bearer token.
@cascade-commerce/api/widgetThe widget API, called from the browser.Publishable key, plus a signature for anything personal.

The admin API

There is no default base URL, so set one before the first call. Keep this on your server: a secret key that reaches a browser is a secret key that has leaked.

import { client, getReviews } from "@cascade-commerce/api/admin"

client.setConfig({
  baseUrl: "https://api.cascade.dev",
  auth: () => process.env.CASCADE_SECRET_KEY,
})

const { data } = await getReviews({ query: { limit: 20 } })

Function names follow the method and path, so POST /products/import is postProductsImport and DELETE /customers/{id} is deleteCustomersById. Path parameters go in path, query parameters in query, and a request body in body.

Every request and response shape is exported as a type:

import type { GetReviewsData, GetReviewsResponse } from "@cascade-commerce/api/admin"

Errors

Calls do not throw on a failed response. Check error and response, which carries the status:

const result = await getReviews({ query: { limit: 20 } })
if (result.error !== undefined || !result.response.ok) {
  // result.error is the { message, code } body documented in Errors
}

See Errors for the codes.

The widget API

The widget API takes a publishable key, which is safe to ship to the browser. Customer-specific endpoints also take the signed email and timestamp generated on your backend. See Authentication.

import { client, getWidgetsWishlists } from "@cascade-commerce/api/widget"

client.setConfig({ baseUrl: "https://api.cascade.dev" })

const { data } = await getWidgetsWishlists({
  query: { apiPublishableKey, customerEmail, timestamp, signature },
})

If you only want the rendered widgets rather than the data behind them, use the widgets package instead. See Storefront widgets for the embed script and React widgets for the React components, which can be dropped in whole or composed from their parts.

React Query

Query and mutation options are generated for both APIs, behind their own entry points so they load only if you ask for them. @tanstack/react-query version 5 is an optional peer dependency.

import { useQuery } from "@tanstack/react-query"
import { getReviewsOptions } from "@cascade-commerce/api/admin/react-query"

const { data } = useQuery(getReviewsOptions({ query: { limit: 20 } }))

Talking to several organizations

The entry points export one shared client, which suits an application serving a single organization. To hold several at once, build a client each and pass one per call:

import { createClient, createConfig } from "@cascade-commerce/api"
import { getReviews } from "@cascade-commerce/api/admin"

const eu = createClient(createConfig({ baseUrl: "https://api.cascade.dev", auth: () => euKey }))

const { data } = await getReviews({ client: eu, query: { limit: 20 } })

If you are building an application many merchants install, use OAuth rather than asking each of them for a secret key. See Authentication.

A worked example

packages/example-custom-store uses this client for its whole integration, in one file. See Custom integration.