> ## Documentation Index
> Fetch the complete documentation index at: https://www.help.creatora.io/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> When building or modifying an integration with the Creatora API, start with https://www.help.creatora.io/en/api/build-with-ai.md. Retrieve the current GraphQL SDL from https://api.creatora.io/sdl before relying on API schema information.

# Compare sales of a Course’s Offers

> Compare successful paid purchases across Offers containing a Course.

Find which Offers containing a Course brought in paid purchases during a period. Replace the Course ID.

This example uses **September 1, 2026 at 00:00 UTC** (`1788220800000`) through **October 1, 2026 at 00:00 UTC**, exclusive (`1790812800000`). Replace both timestamps for your period and timezone. The request starts one millisecond earlier because the API date bounds are strict.

## Request

<RequestExample>
  ```graphql theme={null}
  {
    orders(course: { contains: ["22222222-2222-4222-8222-222222222222"] }, status: { equals: [succeeded] }, closedOn: { range: [1788220799999, 1790812800000] }) {
      id status closedOn amountNetCharge
      offerSnapshot { offerId name }
    }
  }
  ```
</RequestExample>

<ResponseExample>
  ```json Illustrative response theme={null}
  {
    "data": {
      "orders": [
        {
          "id": "55555555-5555-4555-8555-555555555555",
          "status": "succeeded",
          "closedOn": 1788224400000,
          "amountNetCharge": 80.0,
          "offerSnapshot": {
            "offerId": "44444444-4444-4444-8444-444444444444",
            "name": "Drawing Essentials"
          }
        }
      ]
    }
  }
  ```
</ResponseExample>

## Use the result

```javascript theme={null}
const start = 1788220800000;
const end = 1790812800000;
const sales = response.data.orders.filter(order =>
  order.status === "succeeded" && order.closedOn !== null &&
  order.closedOn >= start && order.closedOn < end && order.amountNetCharge > 0
);
const grouped = new Map();
for (const order of sales) {
  const snapshot = order.offerSnapshot;
  const key = snapshot.offerId ?? `historical-order:${order.id}`;
  const row = grouped.get(key) ?? {
    offerId: snapshot.offerId, names: new Set(), purchases: 0, amountCharged: 0
  };
  row.names.add(snapshot.name);
  row.purchases += 1;
  row.amountCharged += order.amountNetCharge;
  grouped.set(key, row);
}
const rows = [...grouped.values()].map(row => ({
  offerId: row.offerId, names: [...row.names], purchases: row.purchases,
  amountCharged: Number(row.amountCharged.toFixed(2))
})).sort((a, b) => b.amountCharged - a.amountCharged);
```

The amount is the whole Order charge, including any other items in the Offer. Use the [Course allocation report](/en/api/recipes/get-revenue-by-course) to attribute amounts to individual Courses. Deleted Offers can have a null `offerId`; the example leaves those purchases separate instead of merging them by a potentially reused name.

The `closedOn` filter in the processing example selects completed purchases; the API date filter also returns Orders created in the period. The request has no list limit. For large reports, request shorter periods and deduplicate Orders by `id`. Amounts use the Platform currency. Manually registered Orders are included.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.