{
  "info": {
    "name": "QR Maker AI — Business API v1",
    "description": "Server-to-server API for Business accounts. Set the collection variable `token` to your API token (Settings → API tokens) — never put a token in a browser or mobile app. Docs: https://qrmaker.ai/docs/business-api-guide.md",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "version": "1.0.0"
  },
  "auth": {
    "type": "bearer",
    "bearer": [
      {
        "key": "token",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "variable": [
    {
      "key": "baseUrl",
      "value": "https://qrmaker.ai/api"
    },
    {
      "key": "token",
      "value": "",
      "description": "Your API token (qrs_…). Leave empty in the file; fill it in after importing."
    }
  ],
  "item": [
    {
      "name": "QR codes",
      "item": [
        {
          "name": "List QR codes",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes"
              ],
              "variable": [],
              "query": [
                {
                  "key": "limit",
                  "value": "50",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "cursor",
                  "value": "",
                  "disabled": true,
                  "description": "Opaque `next_cursor` from the previous page of the same query."
                },
                {
                  "key": "status",
                  "value": "active",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "folder",
                  "value": "",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "external_id",
                  "value": "",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "updated_since",
                  "value": "",
                  "disabled": true,
                  "description": "Unix seconds."
                },
                {
                  "key": "include_deleted",
                  "value": "false",
                  "disabled": true,
                  "description": "With `updated_since`, also return deleted codes as tombstones `{ id, external_id: null, status: \"deleted\", deleted_at, updated_at }` (no target_url or style; match on id). Requires `updated_since`; cannot be combined with `status` or `external_id` (400 otherwise)."
                }
              ]
            },
            "description": "List QR codes\n\nAll codes on the account (API- and dashboard-created), newest first `(created_at DESC, id DESC)`. With `updated_since` the order becomes `(updated_at ASC, id ASC)` for incremental sync (inclusive: `updated_at >= updated_since`). Deleted codes are never returned."
          },
          "response": []
        },
        {
          "name": "Create a QR code (idempotent with external_id)",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes"
              ],
              "variable": [],
              "query": [
                {
                  "key": "include",
                  "value": "svg",
                  "disabled": true,
                  "description": "`svg` adds the full SVG document as `data.svg`."
                }
              ]
            },
            "description": "Create a QR code (idempotent with external_id)\n\nOnly `target_url` is required; its query string is stored and redirected to byte-for-byte.\n\nWith `external_id`: if a code with that `external_id` already exists and has the **same** `target_url`, nothing is created and you get **200** with the existing code and `X-Idempotent-Replay: true` — retries are always safe. A **different** `target_url` returns **409 `EXTERNAL_ID_CONFLICT`** (`params.id` = existing code): POST never retargets; use PATCH. Without `external_id` there is no de-duplication.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"target_url\": \"https://app.example.com/signup?ref=AB12CD\",\n  \"external_id\": \"AB12CD\",\n  \"name\": \"Referral AB12CD\"\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Create up to 100 QR codes",
          "request": {
            "method": "POST",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/batch",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                "batch"
              ],
              "variable": [],
              "query": [
                {
                  "key": "include",
                  "value": "svg",
                  "disabled": true,
                  "description": "`svg` adds the full SVG document as `data.svg`."
                }
              ]
            },
            "description": "Create up to 100 QR codes\n\nEach item is processed independently with the same rules (and idempotency) as single create. The HTTP status is 200; each result has its own `status` and either `data` or `error`. Quota counts successful items (200/201); the whole batch is rejected with 402 if the remaining quota is smaller than the number of items. Rate limit counts the request once.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"items\": [\n    {\n      \"target_url\": \"https://example.com/signup?ref=A1\",\n      \"external_id\": \"A1\"\n    },\n    {\n      \"target_url\": \"https://example.com/signup?ref=A2\",\n      \"external_id\": \"A2\"\n    }\n  ]\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Get a QR code",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "hzu23X",
                  "description": "QR code id (the path of short_link)."
                }
              ],
              "query": [
                {
                  "key": "include",
                  "value": "svg",
                  "disabled": true,
                  "description": "`svg` adds the full SVG document as `data.svg`."
                }
              ]
            },
            "description": "Get a QR code"
          },
          "response": []
        },
        {
          "name": "Update a QR code",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "hzu23X",
                  "description": "QR code id (the path of short_link)."
                }
              ],
              "query": [
                {
                  "key": "include",
                  "value": "svg",
                  "disabled": true,
                  "description": "`svg` adds the full SVG document as `data.svg`."
                }
              ]
            },
            "description": "Update a QR code\n\nSend only the fields to change (at least one). Changing `target_url` re-runs the destination policy and does not change the image. Changing `short_domain` breaks already-printed codes on the old domain. `style` is merged field by field; `style: null` resets it. Deleted codes return 404.",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Delete a QR code",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/:id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                ":id"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "hzu23X",
                  "description": "QR code id (the path of short_link)."
                }
              ],
              "query": []
            },
            "description": "Delete a QR code\n\nPermanent: the short link stops redirecting and the code cannot be restored. Its `external_id` is released for reuse."
          },
          "response": []
        },
        {
          "name": "Get a QR code by external_id",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/by-external-id/:external_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                "by-external-id",
                ":external_id"
              ],
              "variable": [
                {
                  "key": "external_id",
                  "value": "",
                  "description": "Your reference. URL-encode it (e.g. `:` as `%3A`)."
                }
              ],
              "query": [
                {
                  "key": "include",
                  "value": "svg",
                  "disabled": true,
                  "description": "`svg` adds the full SVG document as `data.svg`."
                }
              ]
            },
            "description": "Get a QR code by external_id"
          },
          "response": []
        },
        {
          "name": "Update a QR code by external_id",
          "request": {
            "method": "PATCH",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/by-external-id/:external_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                "by-external-id",
                ":external_id"
              ],
              "variable": [
                {
                  "key": "external_id",
                  "value": "",
                  "description": "Your reference. URL-encode it (e.g. `:` as `%3A`)."
                }
              ],
              "query": [
                {
                  "key": "include",
                  "value": "svg",
                  "disabled": true,
                  "description": "`svg` adds the full SVG document as `data.svg`."
                }
              ]
            },
            "description": "Update a QR code by external_id",
            "body": {
              "mode": "raw",
              "raw": "{}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        },
        {
          "name": "Delete a QR code by external_id",
          "request": {
            "method": "DELETE",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/by-external-id/:external_id",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                "by-external-id",
                ":external_id"
              ],
              "variable": [
                {
                  "key": "external_id",
                  "value": "",
                  "description": "Your reference. URL-encode it (e.g. `:` as `%3A`)."
                }
              ],
              "query": []
            },
            "description": "Delete a QR code by external_id"
          },
          "response": []
        }
      ]
    },
    {
      "name": "Images",
      "item": [
        {
          "name": "Render the QR code as SVG",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/:id/svg",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                ":id",
                "svg"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "hzu23X",
                  "description": "QR code id (the path of short_link)."
                }
              ],
              "query": [
                {
                  "key": "size",
                  "value": "1000",
                  "disabled": true,
                  "description": "width/height in px (viewBox is fixed)."
                },
                {
                  "key": "margin",
                  "value": "4",
                  "disabled": true,
                  "description": "Quiet zone in modules (ISO/IEC 18004 recommends 4)."
                },
                {
                  "key": "download",
                  "value": "1",
                  "disabled": true,
                  "description": "`1` adds `Content-Disposition: attachment`."
                }
              ]
            },
            "description": "Render the QR code as SVG\n\nEncodes `short_link`. `ETag` is `\"{image_version}.{size}.{margin}\"`; send it back in `If-None-Match` to get 304. A logo from your QR Maker uploads is inlined as a data URI (no external references). If the logo could not be inlined, the image is rendered without it, `X-QR-Logo: omitted` is set and the ETag gets a `.nologo` suffix. A 304 counts as a successful call."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Analytics",
      "item": [
        {
          "name": "Analytics for one QR code",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/qrcodes/:id/analytics",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "qrcodes",
                ":id",
                "analytics"
              ],
              "variable": [
                {
                  "key": "id",
                  "value": "hzu23X",
                  "description": "QR code id (the path of short_link)."
                }
              ],
              "query": [
                {
                  "key": "from",
                  "value": "",
                  "disabled": true,
                  "description": "Local start date (inclusive), YYYY-MM-DD."
                },
                {
                  "key": "to",
                  "value": "",
                  "disabled": true,
                  "description": "Local end date (inclusive), YYYY-MM-DD."
                },
                {
                  "key": "tz",
                  "value": "UTC",
                  "disabled": true,
                  "description": "IANA zone (`America/Toronto`, `Asia/Shanghai`) or fixed offset (`+08:00`; encode `+` as `%2B` — an unencoded `+` is tolerated). Invalid → 400 `INVALID_TIMEZONE`."
                }
              ]
            },
            "description": "Analytics for one QR code\n\n`from`/`to` are local dates in `tz`, both inclusive (default: the last 30 days including today; max 366 days). Day boundaries follow the zone's real midnight, including DST changes. Bots/link previews are excluded from `scans` and reported in `bot_scans`. Distributions list the top 20 values plus `{ \"key\": \"other\" }` so they sum to `scans`; empty values are `\"unknown\"` (for referers, no referer = `\"direct\"`).\n\nEvery distribution holds the top 20 plus an `other` row, so each sums to `scans`; empty values are `unknown` (`referers`: `direct`, `apps`: `browser`, `sources`: `none`)."
          },
          "response": []
        },
        {
          "name": "Report across many codes",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/analytics/summary",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "analytics",
                "summary"
              ],
              "variable": [],
              "query": [
                {
                  "key": "from",
                  "value": "",
                  "disabled": true,
                  "description": "Local start date (inclusive), YYYY-MM-DD."
                },
                {
                  "key": "to",
                  "value": "",
                  "disabled": true,
                  "description": "Local end date (inclusive), YYYY-MM-DD."
                },
                {
                  "key": "tz",
                  "value": "UTC",
                  "disabled": true,
                  "description": "IANA zone (`America/Toronto`, `Asia/Shanghai`) or fixed offset (`+08:00`; encode `+` as `%2B` — an unencoded `+` is tolerated). Invalid → 400 `INVALID_TIMEZONE`."
                },
                {
                  "key": "group_by",
                  "value": "code",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "folder",
                  "value": "",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "external_id",
                  "value": "",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "country",
                  "value": "",
                  "disabled": true,
                  "description": "Only count scans from this country (ISO 3166-1 alpha-2, case-insensitive)."
                },
                {
                  "key": "app",
                  "value": "",
                  "disabled": true,
                  "description": "Only count scans opened in this app (a key from `apps`); `browser` = not inside any app."
                },
                {
                  "key": "src",
                  "value": "",
                  "disabled": true,
                  "description": "Only count scans with this placement tag (`?s=`); `none` = untagged."
                },
                {
                  "key": "limit",
                  "value": "50",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "cursor",
                  "value": "",
                  "disabled": true,
                  "description": "Opaque `next_cursor` from the previous page of the same query."
                }
              ]
            },
            "description": "Report across many codes\n\nOne call for a whole sales report. `group_by=code` (default) includes codes with zero scans, ordered `scans DESC, id ASC`; `group_by=folder` rows are `{ folder, codes, scans, unique_visitors }`; `group_by=day` rows are `{ date, scans, unique_visitors }` with zero-filled days. `totals.unique_visitors` is de-duplicated across all codes (not the sum of rows). Results are cached for 60 seconds per account and parameters. Scan filters (`country`, `app`, `src`) can be combined; they restrict which scans are counted (including `totals.bot_scans`) — `group_by=code` still lists codes with zero matching scans."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Scans",
      "item": [
        {
          "name": "Export scan events as CSV",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/scans/export",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "scans",
                "export"
              ],
              "variable": [],
              "query": [
                {
                  "key": "from",
                  "value": "",
                  "disabled": true,
                  "description": "Local start date (inclusive), YYYY-MM-DD."
                },
                {
                  "key": "to",
                  "value": "",
                  "disabled": true,
                  "description": "Local end date (inclusive), YYYY-MM-DD."
                },
                {
                  "key": "tz",
                  "value": "UTC",
                  "disabled": true,
                  "description": "IANA zone (`America/Toronto`, `Asia/Shanghai`) or fixed offset (`+08:00`; encode `+` as `%2B` — an unencoded `+` is tolerated). Invalid → 400 `INVALID_TIMEZONE`."
                },
                {
                  "key": "qrcode_id",
                  "value": "",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "external_id",
                  "value": "",
                  "disabled": true,
                  "description": ""
                }
              ]
            },
            "description": "Export scan events as CSV\n\nAll non-bot scans in the date range (`from`/`to` are local dates in `tz`, both inclusive; default last 30 days, max 366 days), oldest first, as a UTF-8 CSV (with BOM, opens correctly in Excel). Columns: `scanned_at_utc, local_time, qrcode_id, external_id, code_name, country, region, timezone, device, os, os_version, browser, browser_version, app, language, referer, placement, variant, visitor` — new columns are only ever added at the end. Cells that start with `=`, `+`, `-` or `@` get a leading `'` so spreadsheets don't run them as formulas. At most 50,000 rows per call (`X-Export-Truncated: true` when cut). Billed as 1 call per 1,000 rows (at least 1). For continuous syncing use `GET /v1/scans` instead."
          },
          "response": []
        },
        {
          "name": "Incremental scan feed",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/scans",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "scans"
              ],
              "variable": [],
              "query": [
                {
                  "key": "since_id",
                  "value": "0",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "limit",
                  "value": "100",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "qrcode_id",
                  "value": "",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "external_id",
                  "value": "",
                  "disabled": true,
                  "description": ""
                },
                {
                  "key": "include_bots",
                  "value": "false",
                  "disabled": true,
                  "description": ""
                }
              ]
            },
            "description": "Incremental scan feed\n\nScans of your codes with `id > since_id`, ascending. Store `next_since_id` and pass it next time; if `has_more` is true, call again immediately, otherwise wait `poll_after_seconds`. Delivery is at-least-once — de-duplicate by `id`. Scans are written asynchronously after the redirect and usually appear within seconds. A response with no events does not count toward the monthly quota."
          },
          "response": []
        }
      ]
    },
    {
      "name": "Account",
      "item": [
        {
          "name": "Current month's API usage",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/usage",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "usage"
              ],
              "variable": [],
              "query": []
            },
            "description": "Current month's API usage\n\nFree: does not count toward the quota (still rate-limited)."
          },
          "response": []
        },
        {
          "name": "Read the default style for new codes",
          "request": {
            "method": "GET",
            "header": [],
            "url": {
              "raw": "{{baseUrl}}/v1/style",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "style"
              ],
              "variable": [],
              "query": [
                {
                  "key": "include",
                  "value": "svg",
                  "disabled": true,
                  "description": "`svg` adds the full SVG document as `data.svg`."
                }
              ]
            },
            "description": "Read the default style for new codes\n\nThe brand style that codes created through the API inherit. `configured` lists the fields you set; the rest are system defaults. With `include=svg` the response also has a preview image of a sample link (not a real code)."
          },
          "response": []
        },
        {
          "name": "Set (replace) or clear the default style",
          "request": {
            "method": "PUT",
            "header": [
              {
                "key": "Content-Type",
                "value": "application/json"
              }
            ],
            "url": {
              "raw": "{{baseUrl}}/v1/style",
              "host": [
                "{{baseUrl}}"
              ],
              "path": [
                "v1",
                "style"
              ],
              "variable": [],
              "query": [
                {
                  "key": "include",
                  "value": "svg",
                  "disabled": true,
                  "description": "`svg` adds the full SVG document as `data.svg`."
                }
              ]
            },
            "description": "Set (replace) or clear the default style\n\nReplaces the whole default style (it is not merged); `{ \"style\": null }` or `{ \"style\": {} }` clears it. Affects only codes created afterwards: the merged style (default, then the request's own `style` field by field) is stored on each code at creation, so existing codes and their `image_version` never change. Read-only tokens get 403 `TOKEN_READ_ONLY`.",
            "body": {
              "mode": "raw",
              "raw": "{\n  \"style\": {\n    \"fg_color\": \"#0a3d62\",\n    \"dot_style\": \"round\",\n    \"error_level\": \"H\"\n  }\n}",
              "options": {
                "raw": {
                  "language": "json"
                }
              }
            }
          },
          "response": []
        }
      ]
    }
  ]
}
