Skip to content
Cipay
Esc
navigateopen⌘Jpreview
On this page

Products and prices

Search, paginate, and retrieve the published offers shown to buyers.

A product describes what you sell. Its prices are the one-time, recurring, free, or custom-amount offers a buyer can select.

products.list(options)

Use this method for catalog grids, search, and pagination. Search runs on the server across the full catalog.

Input Type Meaning
status draft | published | archived | all Lifecycle filter. Buyer pages normally use published.
query string Server-side name and description search.
pageSize number Maximum items requested for this page.
cursor string Opaque nextCursor from the previous page.
// Ask Cipay for the first matching page of published products.
const page = await cipay.products.list({
  status: "published",
  query: "coffee",
  pageSize: 20,
});

console.log({
  count: page.items.length,
  nextCursor: page.nextCursor,
});
{
  "items": [
    {
      "id": "product_coffee",
      "name": "Coffee membership",
      "description": "Fresh beans delivered monthly.",
      "lifecycle": "published",
      "revision": 4,
      "offers": []
    }
  ],
  "nextCursor": "opaque-next-page-or-null"
}

Continue pagination

Reuse a cursor only with the same query, status, and pageSize. Start again without a cursor when any filter changes.

// null means there are no more results.
const nextPage = page.nextCursor
  ? await cipay.products.list({
      status: "published",
      query: "coffee",
      pageSize: 20,
      cursor: page.nextCursor,
    })
  : null;

products.retrieve(id)

Use this method for a product detail screen or before selecting one of its attached offers. It returns one Product; an unknown or inaccessible ID returns a typed 404 error.

// Product IDs come from products.list or your trusted database mapping.
const product = await cipay.products.retrieve(productId);

console.log({
  id: product.id,
  name: product.name,
  lifecycle: product.lifecycle,
  offerCount: product.offers.length,
  revision: product.revision,
});
{
  "id": "product_coffee",
  "name": "Coffee membership",
  "description": "Fresh beans delivered monthly.",
  "lifecycle": "published",
  "revision": 4,
  "offers": [
    {
      "id": "price_monthly",
      "name": "Monthly",
      "offerType": "recurring",
      "status": "published",
      "currency": "SAR",
      "amountHalalas": 4500,
      "cadence": { "intervalUnit": "month", "intervalCount": 1 }
    }
  ]
}

prices.list(productId, options)

Use this method when you need independent price pagination or merchant tooling. For most buyer product cards, product.offers already contains the selectable offers.

Input Type Meaning
productId string Parent product ID.
status draft | published | retired | all Price lifecycle filter.
pageSize number Maximum prices requested.
cursor string Opaque cursor from the previous response.
// Only published prices should appear in buyer checkout choices.
const prices = await cipay.prices.list(productId, {
  status: "published",
  pageSize: 50,
});

const defaultPrice = prices.items.find((price) => price.isDefault);
console.log({ defaultPrice, nextCursor: prices.nextCursor });
{
  "items": [
    {
      "id": "price_monthly",
      "productId": "product_coffee",
      "name": "Monthly",
      "offerType": "recurring",
      "status": "published",
      "isDefault": true,
      "revision": 2,
      "currency": "SAR",
      "amountHalalas": 4500,
      "cadence": { "intervalUnit": "month", "intervalCount": 1 }
    }
  ],
  "nextCursor": null
}