> ## 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.

# QR codes

> Create, list, update, pause, duplicate, delete and download QR codes.

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

A QR code in GetQR is the image plus a short link it resolves through. Creating a QR code creates its short link too, so you can change the destination later without reprinting the code.

| Method | Path | Description |
| - | - | - |
| `GET` | `/api/v1/qrs` | [List QR codes](#list-qr-codes) |
| `POST` | `/api/v1/qrs` | [Create a QR code](#create-a-qr-code) |
| `GET` | `/api/v1/qrs/{qrId}` | [Get a QR code](#get-a-qr-code) |
| `PATCH` | `/api/v1/qrs/{qrId}` | [Update a QR code](#update-a-qr-code) |
| `PUT` | `/api/v1/qrs/{qrId}` | [Set the paused state](#set-the-paused-state) |
| `POST` | `/api/v1/qrs/{qrId}/pause` | [Pause a QR code](#pause-a-qr-code) |
| `POST` | `/api/v1/qrs/{qrId}/activate` | [Reactivate a QR code](#reactivate-a-qr-code) |
| `POST` | `/api/v1/qrs/{qrId}/duplicate` | [Duplicate a QR code](#duplicate-a-qr-code) |
| `DELETE` | `/api/v1/qrs/{qrId}` | [Delete a QR code](#delete-a-qr-code) |
| `GET` | `/api/v1/qrs/{qrId}/download` | [Download a QR code image](#download-a-qr-code-image) |

> [card] [QR code data by type](https://docs.getqr.com/api/guides/qr-types.md)
>
> The `data` format of each of the 16 types.

> [card] [Customization](https://docs.getqr.com/api/guides/customization.md)
>
> Dot styles, colors, frames and logos.

> [card] [Access rules](https://docs.getqr.com/api/guides/access-rules.md)
>
> Schedule, scan limit and password.

For scan statistics of a QR code, see [Analytics](https://docs.getqr.com/api/endpoints/analytics.md).

## The QR code object

Every QR code endpoint answers with this object, except [Delete](#delete-a-qr-code) and [Download](#download-a-qr-code-image). List returns an array of them.

**id** `string`

Unique ID of the QR code, for example `qr_1EPcVfeHZAY2iNoVLsgW2Aqf`.

**qrType** `string`

QR code type, for example `website`. See [QR code data by type](https://docs.getqr.com/api/guides/qr-types.md) for all 16 values.

**title** `string | null`

Name of the QR code, shown in the dashboard.

**description** `string | null`

Free-text note about the QR code.

**data** `string`

The stored payload. For `wifi`, `vcard`, `social`, `multilink`, `event` and `sms` it is the payload you sent. For every other type it is the short link, so read the destination from `url`.

**archived** `boolean`

`true` when the QR code is paused.

**isStatic** `boolean`

`true` for a static QR code made in the dashboard, which has no short link. The API always creates dynamic QR codes.

**shortLink** `string | null`

Full short link, for example `https://getqr.sh/x7Kd2p1`.

**domain** `string | null`

Domain of the short link.

**key** `string | null`

Slug of the short link.

**keyIsCustom** `boolean`

`true` when the slug was chosen rather than generated.

**url** `string | null`

Destination the short link redirects to.

**ios** `string | null`

Destination for iOS visitors, for `app` QR codes.

**android** `string | null`

Destination for Android visitors, for `app` QR codes.

**scans** `integer`

Total number of scans.

**access** `object`

Access rules. The password itself is never returned. See [Access rules](https://docs.getqr.com/api/guides/access-rules.md).

**properties**

**passwordProtected** `boolean`

Whether visitors must enter a password.

**activeAt** `string | null`

Scheduled start, ISO 8601.

**pauseAt** `string | null`

Scheduled end, ISO 8601.

**scanLimit** `integer | null`

Maximum number of scans.

**designKind** `string`

Read-only. `custom` is a design the API can edit in full. `branded` and `ai` are a Branded design or AI design made in the dashboard. The API can't edit its picture, but keeps it when you change other fields.

**design** `object`

The stored design: `styles`, `frameOptions` and `logoOptions`, each an object or `null`. They have the same shape as the request fields, so you can send them back. See [Customization](https://docs.getqr.com/api/guides/customization.md).

**file** `object | null`

The file of a `pdf`, `image` or `video` QR code: `id`, `name` and `size` in bytes.

**appName** `string | null`

Read-only. Display name of an `app` QR code made in the dashboard.

**pdfBundle** `object | null`

Read-only. A `pdf` QR code with several files, made in the dashboard: `title`, `layout` and `files`.

**imageGallery** `object | null`

Read-only. An `image` QR code with several images, made in the dashboard: `title`, `layout` and `files`.

**createdAt** `string`

Creation date, ISO 8601.

**updatedAt** `string`

Last update date, ISO 8601.

Secrets and internal IDs (`password`, `userId`, `workspaceId`, `projectId`) are never returned.

```json theme={null}
{
  "id": "qr_1EPcVfeHZAY2iNoVLsgW2Aqf",
  "qrType": "website",
  "title": "Landing page",
  "description": null,
  "data": "https://getqr.sh/x7Kd2p1",
  "archived": false,
  "isStatic": false,
  "shortLink": "https://getqr.sh/x7Kd2p1",
  "domain": "getqr.sh",
  "key": "x7Kd2p1",
  "keyIsCustom": false,
  "url": "https://example.com",
  "ios": null,
  "android": null,
  "scans": 128,
  "access": {
    "passwordProtected": false,
    "activeAt": null,
    "pauseAt": null,
    "scanLimit": null
  },
  "designKind": "custom",
  "design": {
    "styles": { "dotsOptions": { "type": "rounded", "color": "#1E40AF" }, … },
    "frameOptions": { "id": "card", "text": "Scan me!", … },
    "logoOptions": { "type": "suggested", "id": "logo-website-3", "scalePercent": 25 }
  },
  "file": null,
  "appName": null,
  "pdfBundle": null,
  "imageGallery": null,
  "createdAt": "2026-08-01T10:00:00.000Z",
  "updatedAt": "2026-08-01T10:00:00.000Z"
}
```

## List QR codes

`GET /api/v1/qrs`

Returns the QR codes in your workspace, one page at a time.

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

Page to return, 1 or more.

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

QR codes per page, from 1 to 100. A larger value is rejected.

**search** `string`

Matches the QR code's title. Queries longer than 2 characters also match the stored `data`. For link types the stored `data` is the short link, so destination URLs aren't searchable.

**sortBy** `string` (default: createdAt)

Field to sort by: `createdAt`, `updatedAt`, `clicks` (total scans), `lastClicked` (latest scan) or `type`. `type` always sorts descending and ignores `sortOrder`.

**sortOrder** `string` (default: desc)

Sort direction: `asc` or `desc`.

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

Include paused QR codes.

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

Return only paused QR codes. Overrides `showArchived`.

Boolean parameters take the strings `true` or `false`. Request the next page while `pagination.hasMore` is `true`. See [Pagination](https://docs.getqr.com/api/introduction.md#pagination).

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

```json 200 theme={null}
{
  "data": [
    {
      "id": "qr_1EPcVfeHZAY2iNoVLsgW2Aqf",
      "qrType": "website",
      "title": "Landing page",
      "shortLink": "https://getqr.sh/x7Kd2p1",
      "url": "https://example.com",
      "scans": 128,
      "…": "…"
    }
  ],
  "pagination": { "page": 1, "pageSize": 100, "total": 1, "hasMore": false }
}
```

## Create a QR code

`POST /api/v1/qrs`

Creates a QR code and its short link together. Answers `201 Created` with the new [QR code](#the-qr-code-object).

**Idempotency-Key** `string`

Your own retry token. Repeating the request with the same key within 24 hours returns the original response instead of creating a second QR code. See [Retries and duplicates](#retries-and-duplicates).

**qrType** `string` *required*

What the QR code encodes. It also sets the format `data` must be in. One of `website`, `pdf`, `image`, `video`, `whatsapp`, `social`, `wifi`, `app`, `feedback`, `vcard`, `sms`, `payment`, `location`, `multilink`, `email`, `event`.

**data** `string` *required*

The type's payload, checked against `qrType`. An empty string skips the check. The format of each type is in [QR code data by type](https://docs.getqr.com/api/guides/qr-types.md).

**link** `object`

The short link the QR code resolves through. Optional: left out, `link.url` follows `data`.

**properties**

**url** `string`

Destination the short link redirects to. Omitted or empty, it defaults to `data`. When both are sent and differ, `link.url` wins. `vcard`, `social`, `multilink` and `event` QR codes always point at their hosted page, and `pdf`, `image` and `video` QR codes with a `fileId` at the file. Accepted schemes: `http:`, `https:`, `wifi:`, `mailto:`, `sms:`, `begin:`.

**domain** `string`

Domain of the short link. It must be a live domain of your workspace: another domain gets `403`, and a domain that isn't live yet gets `422`. Defaults to the workspace's default domain.

**key** `string`

Short link slug, 3 to 15 characters, stored lowercase. A slug that isn't allowed gets `422`, and one that is taken gets `409`. A random 7-character slug is generated when omitted.

**ios** `string | null`

Destination URL for visitors on iOS, for `app` QR codes.

**android** `string | null`

Destination URL for visitors on Android, for `app` QR codes.

**title** `string | null`

Link preview title (`og:title`), stored on the short link. Different from the QR code's own `title`. Nothing displays it yet.

**description** `string | null`

Link preview description (`og:description`), stored on the short link. Nothing displays it yet.

**expiresAt, expiredUrl** `—`

Not available on this API: sending either gets `422`. Use `access.pauseAt` to stop the QR code at a given time.

**title** `string`

Name of the QR code, shown in the dashboard. Trimmed, 1 to 40 characters. Left out, the QR code is untitled.

**description** `string`

Free-text note about the QR code. Up to 280 characters.

**fileId** `string`

The file of a `pdf`, `image` or `video` QR code, uploaded with the matching target. For `vcard`, `social` and `multilink`, an optional profile image uploaded with the `logo` target. `event` accepts it too, but its page reads the cover from `data.fileId`. Other types get `422`. Upload the file with [Files](https://docs.getqr.com/api/endpoints/files.md) first. See [Files in QR codes](https://docs.getqr.com/api/guides/qr-types.md#files-in-qr-codes).

**templateId** `string`

[Template](https://docs.getqr.com/api/endpoints/templates.md) whose design is applied to the new QR code. Design fields you send are merged on top of it. A Branded design or AI design template gets `422` (`art_template_unsupported`). An unknown template, or one from another workspace, gets `404`.

**styles** `object`

Dot and corner shapes and colors. See [Customization](https://docs.getqr.com/api/guides/customization.md).

**frameOptions** `object`

Frame drawn around the QR code and its call-to-action text. See [Customization](https://docs.getqr.com/api/guides/customization.md).

**logoOptions** `object`

Logo in the center: a suggested logo or your own file uploaded with the `logo` target. An unknown file, an unfinished upload or a file from another target is rejected. See [Customization](https://docs.getqr.com/api/guides/customization.md).

**access** `object`

Schedule, scan limit and password protection. See [Access rules](https://docs.getqr.com/api/guides/access-rules.md).

**properties**

**activeAt** `string | null`

Scheduled start, ISO 8601.

**pauseAt** `string | null`

Scheduled end, ISO 8601.

**scanLimit** `integer | null`

Maximum number of scans, a positive integer.

**password** `string | null`

Password visitors must enter. Sending it turns protection on.

**passwordProtected** `boolean`

Turns protection off or back on, keeping the stored password.

**archived** `boolean`

Whether the QR code is paused. `true` creates it paused: scans show the paused page instead of the destination.

Unknown fields are dropped without an error. See [Not supported via the API](https://docs.getqr.com/api/guides/qr-types.md#not-supported-via-the-api).

```bash cURL theme={null}
curl -X POST "https://getqr.com/api/v1/qrs" \
  -H "Authorization: Bearer $GETQR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: landing-page-2026-08" \
  -d '{
    "qrType": "website",
    "data": "https://example.com",
    "title": "Landing page",
    "access": { "scanLimit": 500 }
  }'
```

```json 201 theme={null}
{
  "id": "qr_1EPcVfeHZAY2iNoVLsgW2Aqf",
  "qrType": "website",
  "title": "Landing page",
  "data": "https://getqr.sh/x7Kd2p1",
  "shortLink": "https://getqr.sh/x7Kd2p1",
  "url": "https://example.com",
  "scans": 0,
  "access": { "passwordProtected": false, "activeAt": null, "pauseAt": null, "scanLimit": 500 },
  "…": "…"
}
```

### Retries and duplicates

* **With a key.** With an `Idempotency-Key` header, the response is replayed for 24 hours.
* **Without a key.** An identical body sent within 30 seconds is treated as a duplicate.
* **Replays.** A replay returns the stored response with `x-idempotent-replay: true`. A new QR code returns `false`.
* **In flight.** A second request while the first is still running gets `409 conflict`.
* **Failures.** A failed create releases the key at once, so you can retry with the same key.
* **Best effort.** If the guard is unavailable, creates go through unprotected.

See also [Idempotency](https://docs.getqr.com/api/introduction.md#idempotency).

## Get a QR code

`GET /api/v1/qrs/{qrId}`

Returns a [QR code](#the-qr-code-object) with its short link, access rules, design and, for file-based types, its file.

**qrId** `string` *required*

ID of the QR code, from the list or create response.

```bash cURL theme={null}
curl "https://getqr.com/api/v1/qrs/qr_1EPcVfeHZAY2iNoVLsgW2Aqf" \
  -H "Authorization: Bearer $GETQR_API_KEY"
```

The response is the full [QR code object](#the-qr-code-object).

## Update a QR code

`PATCH /api/v1/qrs/{qrId}`

Changes the content, destination, design or access rules of a QR code. Send only the fields you want to change. Answers with the updated [QR code](#the-qr-code-object).

**qrId** `string` *required*

ID of the QR code.

The body takes the same fields as [Create a QR code](#create-a-qr-code), all optional, with these differences:

* **`templateId`.** Not accepted.
* **`link`.** Partial. The current destination is kept when you omit `link.url`. `link.domain` and `link.key` get `422`: the short link is what the printed code encodes, so create a new QR code to use a different one.
* **`data`.** Checked against the resulting type only when `data` or `qrType` changes. Switching `qrType` without matching `data` is rejected. See [Switching type](https://docs.getqr.com/api/guides/qr-types.md#switching-type).
* **Design.** `styles`, `frameOptions` and `logoOptions` are merged into the stored design, so a partial object changes only what it names. Picking another logo replaces it but keeps its size.
* **`access`.** Each key is applied when present. `null` clears a rule. Access rules belong under `access`: sending them under `link` gets `422`.
* **`archived`.** Pauses or reactivates the QR code and its short link together, like [Pause](#pause-a-qr-code) and [Reactivate](#reactivate-a-qr-code).

```bash cURL theme={null}
curl -X PATCH "https://getqr.com/api/v1/qrs/qr_1EPcVfeHZAY2iNoVLsgW2Aqf" \
  -H "Authorization: Bearer $GETQR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Autumn campaign",
    "access": { "password": "s3cr3t", "passwordProtected": true }
  }'
```

```json 200 theme={null}
{
  "id": "qr_1EPcVfeHZAY2iNoVLsgW2Aqf",
  "title": "Autumn campaign",
  "access": { "passwordProtected": true, "activeAt": null, "pauseAt": null, "scanLimit": null },
  "…": "…"
}
```

What each type lets you change after printing is listed in [QR code data by type](https://docs.getqr.com/api/guides/qr-types.md).

## Set the paused state

`PUT /api/v1/qrs/{qrId}`

Sets the paused state directly. [Pause](#pause-a-qr-code) and [Reactivate](#reactivate-a-qr-code) do the same and read more clearly.

**qrId** `string` *required*

ID of the QR code.

**archived** `boolean` *required*

`true` to pause the QR code, `false` to reactivate it.

```bash cURL theme={null}
curl -X PUT "https://getqr.com/api/v1/qrs/qr_1EPcVfeHZAY2iNoVLsgW2Aqf" \
  -H "Authorization: Bearer $GETQR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "archived": true }'
```

```json 200 theme={null}
{
  "id": "qr_1EPcVfeHZAY2iNoVLsgW2Aqf",
  "archived": true,
  "…": "…"
}
```

## Pause a QR code

`POST /api/v1/qrs/{qrId}/pause`

Stops the QR code from resolving to its destination: scans show the paused page instead. The printed code and its short link stay valid. No request body.

**qrId** `string` *required*

ID of the QR code.

```bash cURL theme={null}
curl -X POST "https://getqr.com/api/v1/qrs/qr_1EPcVfeHZAY2iNoVLsgW2Aqf/pause" \
  -H "Authorization: Bearer $GETQR_API_KEY"
```

```json 200 theme={null}
{
  "id": "qr_1EPcVfeHZAY2iNoVLsgW2Aqf",
  "archived": true,
  "…": "…"
}
```

## Reactivate a QR code

`POST /api/v1/qrs/{qrId}/activate`

Makes a paused QR code resolve to its destination again. Any schedule and scan limit still apply. No request body.

**qrId** `string` *required*

ID of the QR code.

```bash cURL theme={null}
curl -X POST "https://getqr.com/api/v1/qrs/qr_1EPcVfeHZAY2iNoVLsgW2Aqf/activate" \
  -H "Authorization: Bearer $GETQR_API_KEY"
```

```json 200 theme={null}
{
  "id": "qr_1EPcVfeHZAY2iNoVLsgW2Aqf",
  "archived": false,
  "…": "…"
}
```

## Duplicate a QR code

`POST /api/v1/qrs/{qrId}/duplicate`

Creates a copy with the same content and design. No request body. Answers `201 Created` with the new [QR code](#the-qr-code-object).

**qrId** `string` *required*

ID of the QR code to copy.

* **Short link.** The copy gets its own short link, with a random slug on the workspace's default domain, not the source's domain. Its scans are counted separately.
* **Title.** The title gets a ` (Copy)` suffix. The result stays within 40 characters: a long title is shortened first. An untitled QR code stays untitled.
* **Not copied.** Access rules (password, schedule, scan limit) and the paused state. The copy is always active.
* **Files.** PDF and image files, including bundle and gallery files, are copied, so the copy owns them. Video files and design files, such as logos, are shared with the source.

```bash cURL theme={null}
curl -X POST "https://getqr.com/api/v1/qrs/qr_1EPcVfeHZAY2iNoVLsgW2Aqf/duplicate" \
  -H "Authorization: Bearer $GETQR_API_KEY"
```

```json 201 theme={null}
{
  "id": "qr_7Hk2PqWmX9cTnV4sLbR8YdZe",
  "title": "Landing page (Copy)",
  "shortLink": "https://getqr.sh/p2Wq9dL",
  "url": "https://example.com",
  "archived": false,
  "scans": 0,
  "…": "…"
}
```

## Delete a QR code

`DELETE /api/v1/qrs/{qrId}`

Deletes the QR code and its short link. Answers with the deleted ID.

> [!WARNING]
>
> Deleting is permanent. The printed code and its short link stop working, and the scan history is no longer reachable. [Pause](#pause-a-qr-code) the QR code instead if you may need it again.

**qrId** `string` *required*

ID of the QR code.

**id** `string`

ID of the deleted QR code.

**deleted** `boolean`

Always `true`.

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

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

## Download a QR code image

`GET /api/v1/qrs/{qrId}/download`

Renders the QR code with its design and returns the file.

**qrId** `string` *required*

ID of the QR code to render, from the list or create response.

**format** `string` (default: jpg)

Output format: `jpg`, `png`, `svg`, `pdf` (an A4 page) or `eps`. A Branded design or AI design downloads as `jpg`, `png` or `pdf` only.

**resolution** `integer` (default: 1024)

Image size in pixels: `1024`, `2048` or `4096`. `svg` and `pdf` ignore it. A Branded design or AI design downloads at `1024` only.

| `format` | `Content-Type` | File name |
| - | - | - |
| `jpg` | `image/jpeg` | `<title>-<resolution>px.jpg` |
| `png` | `image/png` | `<title>-<resolution>px.png` |
| `svg` | `image/svg+xml` | `<title>.svg` |
| `pdf` | `application/pdf` | `<title>.pdf` |
| `eps` | `application/postscript` | `<title>-<resolution>px.eps` |

* **Body.** The response body is the file. The suggested file name is in the `Content-Disposition` header, built from the title, or `qr-code` for an untitled QR code.
* **Caching.** Responses carry an `ETag` and `Cache-Control: private, max-age=3600, must-revalidate`. Send the `ETag` back in `If-None-Match` to get `304 Not Modified` when the QR code hasn't changed.
* **Errors.** An unsupported format or resolution gets `400 bad_request`. The error message names the reason: `qr_download_invalid_format`, `qr_download_invalid_resolution`, `qr_download_art_format_unsupported` or `qr_download_art_resolution_unsupported`.

```bash cURL theme={null}
curl "https://getqr.com/api/v1/qrs/qr_1EPcVfeHZAY2iNoVLsgW2Aqf/download?format=png&resolution=1024" \
  -H "Authorization: Bearer $GETQR_API_KEY" \
  --output qr-code.png
```

```http 200 theme={null}
HTTP/1.1 200 OK
Content-Type: image/png
Content-Disposition: attachment; filename="landing-page-1024px.png"
ETag: "9f2c0e1b5a7d43c8b016e2f4a9d5c3718be40f92"
Cache-Control: private, max-age=3600, must-revalidate

<binary image data>
```

## Access rules

Send an `access` object on create or update to schedule a start and an end, cap the number of scans or require a password. Omitted rules stay unchanged, and `null` clears one. The full behavior, with examples, is in [Access rules](https://docs.getqr.com/api/guides/access-rules.md).

## Design objects

`styles`, `frameOptions` and `logoOptions` set the dot and corner shapes, colors, frame and logo. They work the same on QR codes, [templates](https://docs.getqr.com/api/endpoints/templates.md) and [bulk creations](https://docs.getqr.com/api/endpoints/bulk-qr-creations.md). Unknown shapes, frames or logos are rejected. All accepted values and a worked example are in [Customization](https://docs.getqr.com/api/guides/customization.md).

## Common issues

> [accordion] 422 when setting a password, schedule or scan limit
>
> Send the rule under `access`, not under `link`.

> [accordion] 422 when changing link.domain or link.key
>
> The short link can't change after creation, because the printed code encodes it. Create a new QR code instead.

> [accordion] 422 "Expected … for qrType"
>
> `data` doesn't match the format of `qrType`. Check the type in [QR code data by type](https://docs.getqr.com/api/guides/qr-types.md).

> [accordion] 409 conflict when creating a QR code
>
> An identical creation is still running, or `link.key` is taken. Retry once the first request finishes. With an `Idempotency-Key`, the retry returns the original QR code.

> [accordion] The download is a JPEG, not a PNG
>
> The parameters are `format` and `resolution`, and `format` defaults to `jpg`. Send `format=png`.

> [accordion] 404 for a QR code I can see in the dashboard
>
> Every request runs in the workspace of your API key. Check that the QR code belongs to it. See [Authentication](https://docs.getqr.com/api/authentication.md).

## What's next

> [card] [QR code data by type](https://docs.getqr.com/api/guides/qr-types.md)

> [card] [Customization](https://docs.getqr.com/api/guides/customization.md)

> [card] [Access rules](https://docs.getqr.com/api/guides/access-rules.md)

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


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