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

# Reports

> Export a one-off scan report or schedule recurring report emails.

> [!NOTE]
>
> The GetQR API is in beta and is available to selected workspaces. Details may change before the general release.

Reports summarize scans per QR code for a completed day, week or month. Export one right away, or schedule a report that is emailed on a regular basis.

| Method | Path | Description |
| - | - | - |
| `POST` | `/api/v1/reports` | [Export a report](#export-a-report) |
| `GET` | `/api/v1/reports/schedules` | [List scheduled reports](#list-scheduled-reports) |
| `POST` | `/api/v1/reports/schedules` | [Schedule a report](#schedule-a-report) |
| `PATCH` | `/api/v1/reports/schedules/{id}` | [Update a scheduled report](#update-a-scheduled-report) |
| `DELETE` | `/api/v1/reports/schedules/{id}` | [Delete a scheduled report](#delete-a-scheduled-report) |

## Headers

**Authorization** `string` *required*

`Bearer` followed by your API key. See [Authentication](https://docs.getqr.com/api/authentication.md).

**Content-Type** `string`

`application/json`. Required on `POST` and `PATCH` requests.

## Scope

One-off and scheduled reports both take a `scope`:

| `scope` | Covers | `qrIds` |
| - | - | - |
| `all` | The QR codes in your workspace | Omit |
| `selected` | A chosen set of QR codes | One or more IDs |
| `single` | Exactly one QR code | Exactly one ID |

A report lists at most 50 QR codes. With `all`, these are the most recently created active QR codes; paused codes are left out. With `selected` and `single`, paused codes are included. QR codes without a short link have no scans and are skipped.

## Period

The period is always the last completed one, so a report never includes today's partial data. Its boundaries are midnight in the report's timezone.

| `period` or `frequency` | Covers |
| - | - |
| `daily` | The previous day |
| `weekly` | The previous week, Monday to Sunday |
| `monthly` | The previous calendar month |

## Export a report

`POST /api/v1/reports`

Builds a report for the last completed period and returns it in the response.

**scope** `string` *required*

`all`, `selected` or `single`. See [Scope](#scope).

**period** `string` *required*

`daily`, `weekly` or `monthly`. See [Period](#period).

**format** `string` *required*

`json` returns the report in the response body. `csv` and `pdf` return a file download.

**qrIds** `string[]`

QR codes to cover. Required for `selected` (one or more IDs) and `single` (exactly one ID). Omit it for `all`.

**timezone** `string` (default: UTC)

IANA timezone the period boundaries are aligned to, for example `America/New_York`. An unknown timezone returns `422`.

**locale** `string` (default: en)

Language of the PDF, for example `en` or `de`. An unsupported value falls back to English. Ignored by `csv` and `json`.

**name** `string`

Title shown on the PDF, up to 40 characters. Ignored by `csv` and `json`.

### JSON response

**periodStart** `string`

First day of the period, `YYYY-MM-DD`.

**periodEnd** `string`

First day after the period, `YYYY-MM-DD`. The period ends at midnight at the start of this day.

**qrs** `object[]`

One entry per QR code.

**properties**

**qrId** `string`

ID of the QR code.

**name** `string`

Title of the QR code, or `Untitled QR`.

**type** `string`

QR code type, for example `website`.

**totalScans** `integer`

Total scans in the period.

**uniqueScans** `integer`

Unique scans in the period.

**topGeography** `string`

Country code with the most scans, or `—` without scans.

**topDevice** `string`

Device with the most scans, or `—`.

**topOs** `string`

Operating system with the most scans, or `—`.

**topBrowser** `string`

Browser with the most scans, or `—`.

### CSV and PDF responses

The body is the file. `Content-Disposition` names it after the period, for example `report-2026-08-10_2026-08-17.csv`. The CSV has one row per QR code with the columns `QR ID`, `QR name`, `QR type`, `Total scans`, `Unique scans`, `Top geography`, `Top device`, `Top OS` and `Top browser`.

```bash JSON theme={null}
curl -X POST "https://getqr.com/api/v1/reports" \
  -H "Authorization: Bearer $GETQR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "scope": "selected",
    "qrIds": ["clw3n7t1x0002ab0d5mqe8pkr"],
    "period": "weekly",
    "format": "json",
    "timezone": "America/New_York"
  }'
```

```bash PDF theme={null}
curl -X POST "https://getqr.com/api/v1/reports" \
  -H "Authorization: Bearer $GETQR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "scope": "all", "period": "monthly", "format": "pdf", "locale": "de" }' \
  --output report.pdf
```

```json 200 theme={null}
{
  "periodStart": "2026-08-10",
  "periodEnd": "2026-08-17",
  "qrs": [
    {
      "qrId": "clw3n7t1x0002ab0d5mqe8pkr",
      "name": "Landing page",
      "type": "website",
      "totalScans": 128,
      "uniqueScans": 96,
      "topGeography": "US",
      "topDevice": "Mobile",
      "topOs": "iOS",
      "topBrowser": "Safari"
    }
  ]
}
```

## The scheduled report object

A scheduled report is emailed to the account that created it, at midnight in its timezone.

**id** `string`

ID of the scheduled report.

**name** `string | null`

Label shown in the email subject and in the dashboard.

**frequency** `string`

`daily`, `weekly` or `monthly`.

**scope** `string`

`all`, `selected` or `single`.

**qrIds** `string[] | null`

QR codes the report covers with the `selected` and `single` scopes. `null` when no IDs were sent.

**filters** `null`

Always `null`. Reserved.

**includePdf** `boolean`

Whether a PDF is attached to the email.

**status** `string`

`active` or `paused`.

**timezone** `string`

IANA timezone the send time and the period are aligned to.

**locale** `string`

Language of the email and the PDF.

**nextRunAt** `string`

When the next email is due, ISO 8601: the next midnight (`daily`), the next Monday (`weekly`) or the 1st of the next month (`monthly`), in the report's timezone.

**lastRunAt** `string | null`

When the last email was sent, ISO 8601.

**createdAt** `string`

Creation date, ISO 8601.

**updatedAt** `string`

Last update date, ISO 8601.

## List scheduled reports

`GET /api/v1/reports/schedules`

Returns the scheduled reports of your workspace, including those created by other members, newest first. The list is paginated: see [Pagination](https://docs.getqr.com/api/introduction.md#pagination).

**page** `integer` (default: 1)

Page to return, 1 or higher.

**pageSize** `integer` (default: 100)

Results per page, 1 to 100.

```bash cURL theme={null}
curl "https://getqr.com/api/v1/reports/schedules?page=1&pageSize=100" \
  -H "Authorization: Bearer $GETQR_API_KEY"
```

```json 200 theme={null}
{
  "data": [
    {
      "id": "clx8f2k9a0001qk0c8vhd3xyz",
      "name": "Weekly campaign digest",
      "frequency": "weekly",
      "scope": "selected",
      "qrIds": ["clw3n7t1x0002ab0d5mqe8pkr", "clw3n7t1x0004ab0d9rzu2wfh"],
      "filters": null,
      "includePdf": true,
      "status": "active",
      "timezone": "America/New_York",
      "locale": "en",
      "nextRunAt": "2026-08-10T04:00:00.000Z",
      "lastRunAt": "2026-08-03T04:00:12.000Z",
      "createdAt": "2026-07-01T12:34:56.000Z",
      "updatedAt": "2026-07-28T09:12:00.000Z"
    }
  ],
  "pagination": { "page": 1, "pageSize": 100, "total": 1, "hasMore": false }
}
```

## Schedule a report

`POST /api/v1/reports/schedules`

Creates a report that is emailed on a regular basis. `nextRunAt` is calculated from the frequency and the timezone.

> [!NOTE]
>
> A QR code can belong to only one scheduled report per frequency. An overlapping schedule returns `409 conflict`.

A report with the `all` scope overlaps every other report of the same frequency. Paused reports still count.

**frequency** `string` *required*

How often the report is sent: `daily`, `weekly` or `monthly`. Also sets the period it covers. See [Period](#period).

**scope** `string` *required*

`all`, `selected` or `single`. See [Scope](#scope).

**timezone** `string` *required*

IANA timezone the send time and the period are aligned to, for example `America/New_York`. An unknown timezone returns `422`.

**locale** `string` *required*

Language of the email and the PDF, for example `en` or `de`. An unsupported value falls back to English. PDFs in `zh`, `ja`, `ko` and `ar` are rendered in English.

**qrIds** `string[]`

QR codes to cover. Required for `selected` (one or more IDs) and `single` (exactly one ID). Every ID must be a QR code in your workspace, or the request returns `404`.

**name** `string`

Label shown in the email subject and in the dashboard, up to 40 characters.

**includePdf** `boolean` (default: false)

Attach a PDF version of the report to the email.

```bash cURL theme={null}
curl -X POST "https://getqr.com/api/v1/reports/schedules" \
  -H "Authorization: Bearer $GETQR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Weekly campaign digest",
    "frequency": "weekly",
    "scope": "selected",
    "qrIds": ["clw3n7t1x0002ab0d5mqe8pkr"],
    "includePdf": true,
    "timezone": "America/New_York",
    "locale": "en"
  }'
```

```json 200 theme={null}
{
  "id": "clx8f2k9a0001qk0c8vhd3xyz",
  "name": "Weekly campaign digest",
  "frequency": "weekly",
  "scope": "selected",
  "qrIds": ["clw3n7t1x0002ab0d5mqe8pkr"],
  "filters": null,
  "includePdf": true,
  "status": "active",
  "timezone": "America/New_York",
  "locale": "en",
  "nextRunAt": "2026-08-10T04:00:00.000Z",
  "lastRunAt": null,
  "createdAt": "2026-08-03T12:34:56.000Z",
  "updatedAt": "2026-08-03T12:34:56.000Z"
}
```

## Update a scheduled report

`PATCH /api/v1/reports/schedules/{id}`

Changes a scheduled report, or pauses and resumes it. Send only the fields you want to change, at least one. Changing the frequency or the timezone, or resuming a paused report, recalculates `nextRunAt`. The one-report-per-frequency rule still applies, so an overlapping change returns `409`.

**id** `string` *required*

ID of the scheduled report. Take it from the list or create response.

**status** `string`

`paused` stops the emails without deleting the schedule. `active` resumes them.

**name** `string`

Label, up to 40 characters.

**frequency** `string`

`daily`, `weekly` or `monthly`.

**scope** `string`

`all`, `selected` or `single`.

**qrIds** `string[]`

QR codes to cover. Every ID must be a QR code in your workspace.

**includePdf** `boolean`

Attach a PDF to the email.

**timezone** `string`

IANA timezone.

**locale** `string`

Language of the email and the PDF.

```bash cURL theme={null}
curl -X PATCH "https://getqr.com/api/v1/reports/schedules/clx8f2k9a0001qk0c8vhd3xyz" \
  -H "Authorization: Bearer $GETQR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Monthly campaign digest",
    "frequency": "monthly",
    "status": "active"
  }'
```

```json 200 theme={null}
{
  "id": "clx8f2k9a0001qk0c8vhd3xyz",
  "name": "Monthly campaign digest",
  "frequency": "monthly",
  "scope": "selected",
  "qrIds": ["clw3n7t1x0002ab0d5mqe8pkr"],
  "filters": null,
  "includePdf": true,
  "status": "active",
  "timezone": "America/New_York",
  "locale": "en",
  "nextRunAt": "2026-09-01T04:00:00.000Z",
  "lastRunAt": "2026-08-03T04:00:12.000Z",
  "createdAt": "2026-07-01T12:34:56.000Z",
  "updatedAt": "2026-08-05T10:15:00.000Z"
}
```

## Delete a scheduled report

`DELETE /api/v1/reports/schedules/{id}`

Deletes the schedule and stops all further emails.

> [!WARNING]
>
> Deleting a scheduled report can't be undone.

**id** `string` *required*

ID of the scheduled report.

```bash cURL theme={null}
curl -X DELETE "https://getqr.com/api/v1/reports/schedules/clx8f2k9a0001qk0c8vhd3xyz" \
  -H "Authorization: Bearer $GETQR_API_KEY"
```

```json 200 theme={null}
{ "id": "clx8f2k9a0001qk0c8vhd3xyz", "deleted": true }
```

## Common issues

> [accordion] 404 when exporting a report
>
> With the `selected` or `single` scope, none of the `qrIds` matched a QR code with a short link in your workspace. Check the IDs.

> [accordion] 404 "QR not found." when scheduling a report
>
> One of the `qrIds` isn't a QR code in your workspace, or it was deleted. Check the IDs with [List QR codes](https://docs.getqr.com/api/endpoints/qr-codes.md).

> [accordion] 409 when scheduling a report
>
> One of the QR codes already belongs to a scheduled report with the same frequency, or a report of that frequency uses the `all` scope. Edit or delete that report, or choose a different frequency.

> [accordion] 404 "Scheduled report not found."
>
> The `id` doesn't match a scheduled report in your workspace. Take it from [List scheduled reports](#list-scheduled-reports).

> [accordion] The report is missing today's scans
>
> Reports cover only the last completed period. Use [Analytics](https://docs.getqr.com/api/endpoints/analytics.md) for live numbers.

## What's next

> [card] [Analytics](https://docs.getqr.com/api/endpoints/analytics.md)

> [card] [Scheduled reports in the app](https://docs.getqr.com/analytics/scheduled-reports.md)

> [card] [Reading reports](https://docs.getqr.com/analytics/reading-reports.md)

> [card] [Errors](https://docs.getqr.com/api/errors.md)


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