> For the complete documentation index, see [llms.txt](https://docs.limio.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.limio.com/api/reporting-api.md).

# Reporting API

Back-office APIs that count and compare what customers did over a date window. Search the order events to list, count or add up orders by type, offer, source or checkout page, and read the checkout conversion rate of each checkout page. Use them for dashboards, reports and questions about sales over time.

## Search Order Events

> Lists the orders of a date window as order events, or counts them and adds up their amounts by a field. Use it for questions about orders over time: the new subscriptions of this week, the cancellations of the last 30 days, the orders for an offer, the revenue by checkout page.\
> \
> Each event is one order. \`orderTypes\` selects the types of order. When it is not given, the answer holds new subscriptions and renewals only, so ask for \`order.cancel\_subscription\` to read cancellations.\
> \
> To count, set \`size=1\` and read \`totalResults\`. To compare, set \`group\_by\`, and set \`metric\` to add up the amounts. To list, read the first page, then send its \`scrollId\` as \`scroll\_id\` to read the next page.\
> \
> The events come from a search index, which can lag an order by some seconds. \`GET /api/objects/limio/orders\` reads the orders themselves, but it has no date, type, offer or source filter, so use this endpoint to find orders.\
> \
> The caller must be a user whose role may read events (\`object:event:\*:read\`). A machine-to-machine token has no role, so it gets a 403.

```json
{"openapi":"3.1.0","info":{"title":"Limio Commerce API","version":"1.0.0"},"tags":[{"name":"Reporting API","description":"Back-office APIs that count and compare what customers did over a date window. Search the order events to list, count or add up orders by type, offer, source or checkout page, and read the checkout conversion rate of each checkout page. Use them for dashboards, reports and questions about sales over time."}],"servers":[{"url":"https://{tenant}/api","description":"Limio environment API","variables":{"tenant":{"default":"your-environment.prod.limio.com","description":"Your Limio environment hostname, e.g. `acme.prod.limio.com` or `acme-sandbox.prod.limio.com`."}}}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth 2.0 Bearer token for authenticated API access. Required for order submission, object management, and administrative operations.\n\nObtain a token via the OAuth flow described in [OAuth Bearer Token](https://docs.limio.com/developers/api-documentation/authentication-overview/oauth-bearer-token).\n\nPass the token in the `Authorization` header: `Bearer <token>`"}},"responses":{"401ApplicationResponse":{"description":"Unauthorized: the request lacks valid authentication credentials. Verify your Bearer token or API key is correct and has not expired.","content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","description":"The unique identifier of the request"},"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"paths":{"/search/elasticEvents":{"get":{"operationId":"searchOrderEvents","summary":"Search Order Events","tags":["Reporting API"],"description":"Lists the orders of a date window as order events, or counts them and adds up their amounts by a field. Use it for questions about orders over time: the new subscriptions of this week, the cancellations of the last 30 days, the orders for an offer, the revenue by checkout page.\n\nEach event is one order. `orderTypes` selects the types of order. When it is not given, the answer holds new subscriptions and renewals only, so ask for `order.cancel_subscription` to read cancellations.\n\nTo count, set `size=1` and read `totalResults`. To compare, set `group_by`, and set `metric` to add up the amounts. To list, read the first page, then send its `scrollId` as `scroll_id` to read the next page.\n\nThe events come from a search index, which can lag an order by some seconds. `GET /api/objects/limio/orders` reads the orders themselves, but it has no date, type, offer or source filter, so use this endpoint to find orders.\n\nThe caller must be a user whose role may read events (`object:event:*:read`). A machine-to-machine token has no role, so it gets a 403.","parameters":[{"in":"query","name":"range","description":"The number of whole days to look back, from 1 to 365. The window starts at 00:00 UTC on the day that is `range` days before today, and ends now. So `range=1` holds yesterday and today. `from` replaces it.","schema":{"type":"integer","minimum":1,"maximum":365,"default":30}},{"in":"query","name":"from","description":"The first day of an explicit window, as an ISO date. The window starts at 00:00 UTC on that day. It replaces `range`, and it can go back more than 365 days.","schema":{"type":"string","format":"date"}},{"in":"query","name":"to","description":"The last day of an explicit window, as an ISO date. The window holds all of that day, in UTC. Without `from`, the window starts where `range` puts it.","schema":{"type":"string","format":"date"}},{"in":"query","name":"orderTypes","description":"The types of order to include, separated by commas. `order.new` is a new subscription. `order.renew` is a renewal. `order.cancel_subscription` is a cancellation. `order.add_offer` adds an offer to a subscription, for example a save offer that a customer takes instead of cancelling. `order.change_offer` changes the offer of a subscription. The index holds no other type, so another value gets a 400.","schema":{"type":"string","default":"order.new,order.renew"}},{"in":"query","name":"offer","description":"Keeps the events whose offer path holds this word, in any case. For example, `digital` finds `/offers2/Digital Monthly UK`. Give one word: a value with a space matches nothing. Only new subscriptions and renewals carry an offer.","schema":{"type":"string","maxLength":200}},{"in":"query","name":"source","description":"Keeps the events from this source, for example `shop`. The value must match exactly.","schema":{"type":"string","maxLength":200}},{"in":"query","name":"status","description":"Keeps the events with this status, for example `submitted`, `processed` or `error`. The value must match exactly.","schema":{"type":"string","maxLength":100}},{"in":"query","name":"checkoutPage","description":"Keeps the orders that went through this checkout page, for example `/checkout/`. The value must match exactly. Only new subscriptions and renewals carry a checkout page.","schema":{"type":"string","maxLength":500}},{"in":"query","name":"filters","description":"More filters, as a JSON array of objects with `field`, `value` and `match`. `field` is one of `offer`, `source`, `eventStatus`, `status`, `checkoutPage`, `orderType`, `currency`, `lmo_offer`, `utm_campaign`, `utm_source`, `utm_medium`, `utm_term` and `utm_content`. `match` is `term`, the default, for an exact match, or `wildcard` to find the value inside the field in any case. An event must match every filter.","schema":{"type":"string","maxLength":2000}},{"in":"query","name":"sort","description":"The order of the events, as `field:direction`. `field` is `created` or `amount`, and `direction` is `asc` or `desc`. Ignored with `group_by`.","schema":{"type":"string","default":"created:desc"}},{"in":"query","name":"size","description":"The number of events on a page, from 1 to 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":10}},{"in":"query","name":"scroll_id","description":"The `scrollId` of the previous page, to read the next page. A page can be continued for 2 minutes after it was read. With `scroll_id`, the other parameters are ignored.","schema":{"type":"string"}},{"in":"query","name":"group_by","description":"Groups the events by this field instead of listing them. The answer holds one bucket for each value of the field, at most 1000, in `aggregation.buckets`, and `results` is empty. `checkoutPage`, `offer`, `currency` and the `utm_*` fields are on new subscriptions and renewals only.","schema":{"type":"string","enum":["checkoutPage","offer","source","orderType","currency","eventStatus","utm_campaign","utm_source","utm_medium","utm_term","utm_content"]}},{"in":"query","name":"metric","description":"What each bucket holds with `group_by`. `count` is the number of events, and the buckets come largest count first. `sum:amount` is the total amount and `avg:amount` the mean amount, and the buckets come largest value first. An amount is in the currency of its order, so filter on `currency` or group by it before you add up amounts.","schema":{"type":"string","enum":["count","sum:amount","avg:amount"],"default":"count"}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","properties":{"results":{"type":"array","description":"The events of this page, newest first unless `sort` says otherwise. Empty with `group_by`.","items":{"type":"object","properties":{"reference":{"type":"string","description":"The order reference."},"orderType":{"type":"string"},"status":{"type":"string"},"createdAt":{"type":"string","description":"When the order was made, in UTC, as `dd/MM/yyyy, HH:mm:ss`. It is not an ISO date."},"currency":{"type":"string"},"eventId":{"type":"string"},"source":{"type":"string"},"offer":{"type":"array","description":"New subscriptions and renewals: the offers of the order, without their catalog folder.","items":{"type":"string"}},"total":{"type":"string","description":"New subscriptions and renewals: the amount of the order, to 2 decimals."},"journey":{"type":"object","description":"New subscriptions and renewals: the checkout page that the order went through.","properties":{"checkout":{"type":"string"}}},"lmo_offer":{"type":"string","description":"New subscriptions and renewals: the offer path in the tracking data of the order."},"utm_campaign":{"type":"string"},"utm_source":{"type":"string"},"utm_medium":{"type":"string"},"utm_term":{"type":"string"},"utm_content":{"type":"string"},"originalOffer":{"type":"string","description":"Cancellations, added offers and offer changes: the name of the offer before the order."},"originalOfferPath":{"type":"string"},"originalProducts":{"type":"string"},"originalNextPayment":{"type":"string","description":"The next payment before the order."},"cancelReason":{"type":"string","description":"Cancellations and added offers: the reason that the customer gave."},"saveOffer":{"type":"string","description":"Added offers: the offer that was added."},"saveProducts":{"type":"string"},"saveNextPayment":{"type":"string"},"switchOffer":{"type":"string","description":"Offer changes: the new offer."},"switchProducts":{"type":"string"},"switchNextPayment":{"type":"string"}}}},"totalResults":{"type":"integer","description":"The number of events that match, on all pages."},"scrollId":{"type":"string","description":"Send it as `scroll_id` to read the next page. Empty with `group_by`."},"aggregation":{"type":"object","description":"Only with `group_by`.","properties":{"groupBy":{"type":"string"},"metric":{"type":"string"},"buckets":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","description":"A value of the field. An offer is a full catalog path, for example `/offers2/Digital Monthly UK`."},"count":{"type":"integer","description":"The number of events with this value."},"value":{"type":"number","description":"The sum or the mean of the amounts. Not there for `count`."}}}}}}}}}}},"400":{"description":"A parameter is not valid, for example an unknown order type or field. The message names the values that are allowed."},"401":{"$ref":"#/components/responses/401ApplicationResponse"},"403":{"description":"The role of the caller may not read events, or the caller has no role."}}}}}}
```

## Get Checkout Conversion Rate

> Answers with the checkout conversion rate of each checkout page: the share of the shop sessions that reached a checkout and then completed an order. It is the number that the Checkout Conversion Rate report of the Limio app shows.\
> \
> The rate counts sessions, not orders. The denominator, \`initiatedCount\`, is the number of sessions with a \`checkoutReached\` event. The numerator, \`completedCount\`, is the number of sessions with an \`orderComplete\` event. The sessions are bucketed by \`journey.checkout\`, the checkout page of the session, and each bucket is one key of the answer. \`conversionRate\` is \`completedCount\` divided by \`initiatedCount\`, as a fraction from 0 to 1. It is 0 when no session reached the checkout. A session counts in \`completedCount\` also when it has no \`checkoutReached\` event, so the rate can be more than 1.\
> \
> \`range\` counts back from today in whole days. The window starts at 00:00 UTC on the day that is \`range\` days before today, and ends now. A session is in the window when one of its events is.\
> \
> The answer leaves out preview pages (\`/\_\_v/.../index.html\`). The key \`""\` holds the sessions that have no checkout page. The key is the page path as the session recorded it, so \`/checkout\` and \`/checkout/\` are two keys. Add the counts of both keys to get the rate of one page. To count orders instead of sessions, use \`GET /api/search/elasticEvents\` with \`group\_by=checkoutPage\`.\
> \
> The caller must be a user whose role may read analytics (\`app:subscriptions:analytics\`) and baskets (\`object:basket:\*:read\`). A machine-to-machine token has no role, so it gets a 403.

```json
{"openapi":"3.1.0","info":{"title":"Limio Commerce API","version":"1.0.0"},"tags":[{"name":"Reporting API","description":"Back-office APIs that count and compare what customers did over a date window. Search the order events to list, count or add up orders by type, offer, source or checkout page, and read the checkout conversion rate of each checkout page. Use them for dashboards, reports and questions about sales over time."}],"servers":[{"url":"https://{tenant}/api","description":"Limio environment API","variables":{"tenant":{"default":"your-environment.prod.limio.com","description":"Your Limio environment hostname, e.g. `acme.prod.limio.com` or `acme-sandbox.prod.limio.com`."}}}],"security":[{"bearerAuth":[]}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"OAuth 2.0 Bearer token for authenticated API access. Required for order submission, object management, and administrative operations.\n\nObtain a token via the OAuth flow described in [OAuth Bearer Token](https://docs.limio.com/developers/api-documentation/authentication-overview/oauth-bearer-token).\n\nPass the token in the `Authorization` header: `Bearer <token>`"}},"responses":{"401ApplicationResponse":{"description":"Unauthorized: the request lacks valid authentication credentials. Verify your Bearer token or API key is correct and has not expired.","content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","description":"The unique identifier of the request"},"code":{"type":"string"},"message":{"type":"string"}}}}}}}},"paths":{"/analytics/checkout/conversion":{"get":{"operationId":"getCheckoutConversionRate","summary":"Get Checkout Conversion Rate","tags":["Reporting API"],"description":"Answers with the checkout conversion rate of each checkout page: the share of the shop sessions that reached a checkout and then completed an order. It is the number that the Checkout Conversion Rate report of the Limio app shows.\n\nThe rate counts sessions, not orders. The denominator, `initiatedCount`, is the number of sessions with a `checkoutReached` event. The numerator, `completedCount`, is the number of sessions with an `orderComplete` event. The sessions are bucketed by `journey.checkout`, the checkout page of the session, and each bucket is one key of the answer. `conversionRate` is `completedCount` divided by `initiatedCount`, as a fraction from 0 to 1. It is 0 when no session reached the checkout. A session counts in `completedCount` also when it has no `checkoutReached` event, so the rate can be more than 1.\n\n`range` counts back from today in whole days. The window starts at 00:00 UTC on the day that is `range` days before today, and ends now. A session is in the window when one of its events is.\n\nThe answer leaves out preview pages (`/__v/.../index.html`). The key `\"\"` holds the sessions that have no checkout page. The key is the page path as the session recorded it, so `/checkout` and `/checkout/` are two keys. Add the counts of both keys to get the rate of one page. To count orders instead of sessions, use `GET /api/search/elasticEvents` with `group_by=checkoutPage`.\n\nThe caller must be a user whose role may read analytics (`app:subscriptions:analytics`) and baskets (`object:basket:*:read`). A machine-to-machine token has no role, so it gets a 403.","parameters":[{"in":"query","name":"range","description":"The number of whole days to look back. Give a whole number.","schema":{"type":"integer","default":30}}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"type":"object","description":"One key for each checkout page.","additionalProperties":{"type":"object","properties":{"initiatedCount":{"type":"integer","description":"The sessions with a `checkoutReached` event."},"completedCount":{"type":"integer","description":"The sessions with an `orderComplete` event."},"conversionRate":{"type":"number","description":"`completedCount` divided by `initiatedCount`, as a fraction. 0 when `initiatedCount` is 0."}}}}}}},"401":{"$ref":"#/components/responses/401ApplicationResponse"},"403":{"description":"The role of the caller may not read analytics or baskets, or the caller has no role."}}}}}}
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.limio.com/api/reporting-api.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
