> ## Documentation Index
> Fetch the complete documentation index at: https://docs.weflayr.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Get performance

> Get cost, bucketed by period and optionally grouped by user, alongside each of the project's key metrics' value and cost-per-unit for the same period.

<Note>
  Performance is computed on internal projects. On a revenue-linked project (tracked by revenue, not key metrics), this route returns a 400: use [Get margin](/api/margin#get-margin) instead.
</Note>

<CodeGroup>
  ```python Python theme={null}
  import weflayr

  client = weflayr.client(api_key="wf-...")
  ```

  ```js Node.js theme={null}
  const weflayr = require('weflayr');

  const client = weflayr.client({ apiKey: 'wf-...' });
  ```

  ```bash cURL theme={null}
  # Passed as a Bearer token on every request
  export WEFLAYR_API_KEY="wf-..."
  ```
</CodeGroup>

## Get performance

<CodeGroup>
  ```python Python theme={null}
  from weflayr.openapi.models import PerformanceInput

  client.get_performance(body=PerformanceInput.from_dict({
      "date_from": "2026-06-01",
      "aggregate": "week",
      "group_by": "user",
      "user_tags": {"region": ["EU", "NA"], "plan": "premium"},
  }))
  ```

  ```js Node.js theme={null}
  await weflayr.api.getPerformance({
    client,
    throwOnError: true,
    body: {
      dateFrom: '2026-06-01',
      aggregate: 'week',
      groupBy: 'user',
      userTags: { region: ['EU', 'NA'], plan: 'premium' },
    },
  });
  ```

  ```bash cURL theme={null}
  curl -X POST https://app.weflayr.com/api/performance/ \
    -H "Authorization: Bearer $WEFLAYR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "date_from": "2026-06-01",
      "aggregate": "week",
      "group_by": "user",
      "user_tags": {"region": ["EU", "NA"], "plan": "premium"}
    }'
  ```
</CodeGroup>

**Output:**

```json theme={null}
{
  "rows": [
    {
      "date_from": "2026-06-01", "date_to": "2026-06-07", "user": "u_123", "cost": 342.87,
      "key_metrics": {
        "Meetings booked": {"value": 134.0, "total_cost": 342.87, "cost_per_unit": 2.56},
        "Tickets resolved": {"value": 556.0, "total_cost": 342.87, "cost_per_unit": 0.62}
      }
    },
    {
      "date_from": "2026-06-01", "date_to": "2026-06-07", "user": "u_456", "cost": 128.05,
      "key_metrics": {
        "Meetings booked": {"value": 40.0, "total_cost": 128.05, "cost_per_unit": 3.20}
      }
    }
  ],
  "next_cursor": null,
  "has_more": false
}
```

`user` is omitted when `group_by` isn't set.

**Input params:** passed in the request body.

<ParamField body="date_from" type="&#x22;YYYY-MM-DD&#x22;" required>
  Start of the period, inclusive.
</ParamField>

<ParamField body="date_to" type="&#x22;YYYY-MM-DD&#x22;">
  End of the period, inclusive. Defaults to today.
</ParamField>

<ParamField body="aggregate" type="&#x22;day&#x22; | &#x22;week&#x22; | &#x22;month&#x22; | &#x22;quarter&#x22; | &#x22;year&#x22; | &#x22;all&#x22;" default="&#x22;day&#x22;">
  One row per period; `"all"` collapses the whole date range into a single row (per `group_by`, if set).
</ParamField>

<ParamField body="group_by" type="&#x22;user&#x22;">
  Split each period into one row per user. Omit for one row per period.
</ParamField>

<ParamField body="users" type="list[string]">
  Restrict to these users. Omit for every user. See [Get customers](/api/metadata#get-customers).
</ParamField>

<ParamField body="filter_users_based_on_features" type="list[string]">
  Restrict to users who used any of these feature tags in the period (i.e. if a user did not use the feature, all its rows are removed).
</ParamField>

<ParamField body="user_tags" type="{tag_key: list[string] | string}">
  Restrict to users carrying these tags (AND across `tag_key`, OR within a `tag_key`'s values).
</ParamField>

<ParamField body="apply_credits" type="boolean" default="false">
  Apply [free AI credits](/configure/free-ai-credits) discounts to `cost`.
</ParamField>

<ParamField body="limit" type="integer" default="100">
  Max number of rows to fetch. Max `1000`.
</ParamField>

<ParamField body="cursor" type="string">
  The route is paginated: pass the previous page's `next_cursor` to fetch the next page. PS: `has_more` from the output says whether another page exists.
</ParamField>
