> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs-parschat.parstechai.com/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs-parschat.parstechai.com/_mcp/server.

# Usage reports

> Messages, units and conversations per robot over any window, with offset paging.

> **Note**
>
> **This endpoint is live.** Everything on this page is callable except the
> [Instagram breakdown by entry point](#instagram-breakdown-by-entry-point), which is still
> pre-release and marked where it begins.

One endpoint reports activity for every robot on your account.

```bash
curl "https://api-chat.parstechai.com/v1/usage?from=2026-09-01T00:00:00Z&to=2026-09-30T23:59:59Z" \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxx"
```

**`Response`**

```json Response
{
  "window": { "from": "2026-09-01T00:00:00Z", "to": "2026-09-30T23:59:59Z" },
  "data": [
    {
      "robot_id": "a3f9c21b4e7d40a8",
      "external_id": "shop_10422",
      "name": "Rose Flower Shop",
      "messages": {
        "total": 1840,
        "units": 1840,
        "by_role": { "client": 900, "ai": 820, "operator": 120 }
      },
      "conversations": { "total": 312 },
      "channels_connected": 1
    }
  ],
  "pagination": { "limit": 50, "offset": 0, "total_count": 128, "has_more": true },
  "metadata": {
    "processed_at": "2026-10-01T09:15:22Z",
    "cache_hit": false
  }
}
```

`by_role` separates AI answers from human ones, which is what you need to show your own customers
how much of their support the automation is carrying.

> **Warning**
>
> **`messages.total` and `messages.units` are not the same number.** A robot using the
> enhanced-accuracy model consumes **two** units per message, so a customer who sent 1,000 messages
> on that model shows `total: 1000` and `units: 2000`.
>
> Reconcile billing against `units`. Show `total` to your customer as a message count.

> **Info**
>
> `external_id` is **your** identifier for the robot. It is `null` until robot creation over the API
> ships, so today every robot returns `null` here — match on `robot_id` in the meantime.

The window defaults to the last 30 days and may not span more than a year. Requesting a wider
window, a `from` after your `to`, or a `limit` above 100 returns `400`.

> **Info**
>
> This reports robot activity, not your remaining balance. It answers "how much did this customer
> use?" rather than "how much is left on the account?". Plan balance is out of scope for this API.
>
> `metadata.processed_at` is the moment the figures are accurate as of. Usage is computed
> periodically, so a conversation from seconds ago may not be counted yet.

## One robot

Pass `robot_id` to narrow the report to a single robot.

```bash
curl "https://api-chat.parstechai.com/v1/usage?robot_id=a3f9c21b4e7d40a8&from=2026-09-01T00:00:00Z&to=2026-09-30T23:59:59Z" \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxx"
```

## Paging

Page with `limit` and `offset`. `pagination.total_count` is the number of robots matching your
query across every page, so you know how many calls to make before you start.

```bash
curl "https://api-chat.parstechai.com/v1/usage?from=2026-09-01T00:00:00Z&to=2026-09-30T23:59:59Z&limit=50&offset=50" \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxx"
```

**`Python`**

```python Python
import math, requests

params = {"from": FROM, "to": TO, "limit": 50, "offset": 0}
first = requests.get(URL, headers=HEADERS, params=params, timeout=30).json()

pages = math.ceil(first["pagination"]["total_count"] / first["pagination"]["limit"])
robots = list(first["data"])

for page in range(1, pages):
    params["offset"] = page * params["limit"]
    robots += requests.get(URL, headers=HEADERS, params=params, timeout=30).json()["data"]
```

## Instagram breakdown by entry point

> **Warning**
>
> **Pre-release — not callable yet.** This section commits to the shape, not to a date. Passing
> `breakdown=source` today returns the standard payload above without the extra fields. Everything
> else on this page is live.

A customer whose volume comes mostly from story replies has a different product than one driven by
comments, and a single `total` hides that.

```bash
curl "https://api-chat.parstechai.com/v1/usage?robot_id=a3f9c21b4e7d40a8&from=2026-09-01T00:00:00Z&to=2026-09-30T23:59:59Z&breakdown=source" \
  -H "Authorization: Bearer pk_live_xxxxxxxxxxxxxxxxxxxx"
```

**`Response`**

```json Response
{
  "data": [
    {
      "robot_id": "rbt_8fK2mQ",
      "external_id": "shop_10422",
      "channel": "instagram",
      "window": { "from": "2026-09-01T00:00:00Z", "to": "2026-09-30T23:59:59Z" },
      "messages": {
        "total": 1840,
        "by_role": { "client": 900, "ai": 820, "operator": 120 }
      },
      "conversations": { "total": 312 },
      "channels_connected": 1,
      "by_source": {
        "direct":        { "conversations": 180, "messages": 1120 },
        "comment":       { "conversations":  84, "messages":  310 },
        "story_reply":   { "conversations":  36, "messages":  290 },
        "story_mention": { "conversations":  12, "messages":  120 }
      },
      "totals": { "conversations": 312, "messages": 1840 }
    }
  ],
  "pagination": { "limit": 50, "offset": 0, "total_count": 1, "has_more": false },
  "metadata": {
    "request_id": "req_8f2Kq9mR",
    "processed_at": "2026-10-01T09:15:22Z"
  }
}
```

> **Info**
>
> `breakdown=source` **adds** fields rather than replacing them. `messages`, `conversations` and
> `channels_connected` are still there, so one parser handles both shapes.

| Source          | Meaning                                           |
| --------------- | ------------------------------------------------- |
| `direct`        | A DM the customer started                         |
| `comment`       | Triggered by a comment on a post                  |
| `story_reply`   | The customer replied to a story                   |
| `story_mention` | The customer mentioned the account in their story |
| `reel`          | Originated from a reel                            |

The same `source` vocabulary appears on every `message` event, so you can attribute an event to its
entry point without a second call.

## Reconciling a gap

If a webhook delivery exhausted its [retries](/documentation/guides/webhook-events#retries), this API is how you find out.
Compare the counts here against what you stored for the same window.