{
  "openapi": "3.1.0",
  "info": {
    "title": "QRGlo API",
    "version": "1",
    "description": "Create and manage dynamic QR codes and short links, read scan statistics and render QR codes and barcodes. Requires a Pro workspace. Human-readable reference: https://qrglo.com/docs/api"
  },
  "servers": [
    {
      "url": "https://qrglo.com/api/v1"
    }
  ],
  "security": [
    {
      "bearer": []
    }
  ],
  "components": {
    "securitySchemes": {
      "bearer": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key from the API page in the app."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "invalid_json",
              "invalid",
              "unsafe",
              "not_a_link_code",
              "data",
              "kind",
              "unauthorized",
              "pro_required",
              "limit",
              "locked",
              "not_found",
              "template_not_found",
              "method_not_allowed",
              "rate_limited",
              "server_error"
            ]
          }
        }
      }
    }
  },
  "paths": {
    "/codes": {
      "get": {
        "operationId": "listCodes",
        "summary": "List codes",
        "description": "Every editable QR code and Smart Link in the workspace, newest first, archived ones included (see \"archived\").",
        "parameters": [
          {
            "name": "kind",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "qr",
                "link"
              ],
              "description": "Only QR codes (qr) or only Smart Links (link). Leave out for both."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "k3v9x2",
                      "name": "Menu",
                      "kind": "qr",
                      "type": "url",
                      "short_url": "https://q.qrglo.com/ab3cd",
                      "target_url": "https://example.com/menu",
                      "active": true,
                      "archived": false,
                      "scans": 128,
                      "tags": [
                        "table-cards"
                      ],
                      "domain": null,
                      "created_at": "2026-10-01T09:30:00.000Z",
                      "updated_at": "2026-10-20T14:02:11.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createCode",
        "summary": "Create a code",
        "description": "Creates an editable code that sends scans to \"url\". Put \"qr_payload\" into any QR renderer, or call GET /qr with it, to get the printable pattern.",
        "parameters": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "url"
                ],
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "Where scans go. http or https; checked against Google Safe Browsing."
                  },
                  "name": {
                    "type": "string",
                    "description": "Your label for the code. Defaults to the link’s host name."
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "qr",
                      "link"
                    ],
                    "description": "\"qr\" (default) for a QR code, \"link\" for a Smart Link with no pattern."
                  },
                  "template": {
                    "type": "string",
                    "description": "A style template id from GET /templates. The code gets that template’s colours, shapes and logo."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "id": "k3v9x2",
                  "name": "Menu",
                  "kind": "qr",
                  "type": "url",
                  "short_url": "https://q.qrglo.com/ab3cd",
                  "target_url": "https://example.com/menu",
                  "active": true,
                  "archived": false,
                  "scans": 128,
                  "tags": [
                    "table-cards"
                  ],
                  "domain": null,
                  "created_at": "2026-10-01T09:30:00.000Z",
                  "updated_at": "2026-10-20T14:02:11.000Z",
                  "qr_payload": "https://q.qrglo.com/ab3cd"
                }
              }
            }
          },
          "400": {
            "description": "invalid_json: The body is not valid JSON. invalid: The URL is not a valid http(s) link, or points at our own short domain. unsafe: Google Safe Browsing lists the URL as malware or phishing.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro. limit: The workspace has reached its code limit.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "template_not_found: No template with that id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/codes/{id}": {
      "get": {
        "operationId": "getCode",
        "summary": "Get a code",
        "description": "One code, with the \"qr_payload\" to render it.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The code id, as returned by list or create."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "id": "k3v9x2",
                  "name": "Menu",
                  "kind": "qr",
                  "type": "url",
                  "short_url": "https://q.qrglo.com/ab3cd",
                  "target_url": "https://example.com/menu",
                  "active": true,
                  "archived": false,
                  "scans": 128,
                  "tags": [
                    "table-cards"
                  ],
                  "domain": null,
                  "created_at": "2026-10-01T09:30:00.000Z",
                  "updated_at": "2026-10-20T14:02:11.000Z",
                  "qr_payload": "https://q.qrglo.com/ab3cd"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found: No such code in this workspace, or no such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateCode",
        "summary": "Update a code",
        "description": "Changes where a printed code goes, renames it, or pauses it. Send only the fields you change. The printed pattern stays the same.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The code id, as returned by list or create."
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [],
                "properties": {
                  "url": {
                    "type": "string",
                    "description": "New destination. Only for link codes (type \"url\")."
                  },
                  "name": {
                    "type": "string",
                    "description": "New label."
                  },
                  "active": {
                    "type": "boolean",
                    "description": "false pauses the code: scans see a \"paused\" page. true turns it back on."
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "id": "k3v9x2",
                  "name": "Menu",
                  "kind": "qr",
                  "type": "url",
                  "short_url": "https://q.qrglo.com/ab3cd",
                  "target_url": "https://example.com/menu-winter",
                  "active": true,
                  "archived": false,
                  "scans": 128,
                  "tags": [
                    "table-cards"
                  ],
                  "domain": null,
                  "created_at": "2026-10-01T09:30:00.000Z",
                  "updated_at": "2026-10-20T14:02:11.000Z"
                }
              }
            }
          },
          "400": {
            "description": "invalid_json: The body is not valid JSON. invalid: The URL is not a valid http(s) link, or points at our own short domain. unsafe: Google Safe Browsing lists the URL as malware or phishing. not_a_link_code: Only link codes have a URL to change; hosted pages (vCard, menu…) are edited in the app.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro. locked: The code is read-only because the plan’s limit was lowered.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found: No such code in this workspace, or no such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "archiveCode",
        "summary": "Archive a code",
        "description": "Archives the code: it stops counting toward your limit and its statistics are kept. It can be restored in the app.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The code id, as returned by list or create."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "id": "k3v9x2",
                  "archived": true
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found: No such code in this workspace, or no such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/codes/{id}/stats": {
      "get": {
        "operationId": "codeStats",
        "summary": "Scan statistics",
        "description": "Totals and a time series for one code. Unique visitors are counted per day, without cookies.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The code id, as returned by list or create."
            }
          },
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "24h",
                "7d",
                "30d",
                "90d",
                "12m",
                "all",
                "custom"
              ],
              "description": "Time range. Default 30d. Buckets are hours (24h), days, or months for long ranges."
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "With window=custom: first day, YYYY-MM-DD (UTC)."
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "With window=custom: last day, YYYY-MM-DD (UTC). Up to 5 years after \"from\"."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "id": "k3v9x2",
                  "window": {
                    "k": "7d",
                    "from": "2026-10-26T00:00:00.000Z",
                    "to": "2026-11-01T18:20:00.000Z",
                    "bucket": "day"
                  },
                  "total": 42,
                  "unique": 37,
                  "series": [
                    {
                      "label": "2026-10-26",
                      "scans": 5
                    },
                    {
                      "label": "2026-10-27",
                      "scans": 8
                    }
                  ],
                  "countries": [
                    {
                      "k": "US",
                      "n": 20
                    },
                    {
                      "k": "DE",
                      "n": 9
                    }
                  ],
                  "devices": [
                    {
                      "k": "mobile",
                      "n": 39
                    },
                    {
                      "k": "desktop",
                      "n": 3
                    }
                  ],
                  "os": [
                    {
                      "k": "iOS",
                      "n": 25
                    },
                    {
                      "k": "Android",
                      "n": 14
                    }
                  ],
                  "browsers": [
                    {
                      "k": "Safari",
                      "n": 24
                    }
                  ],
                  "languages": [
                    {
                      "k": "en",
                      "n": 30
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "not_found: No such code in this workspace, or no such endpoint.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/qr": {
      "get": {
        "operationId": "renderQr",
        "summary": "Render a QR code (SVG)",
        "description": "Draws any text or link as a static QR code. Use it with \"qr_payload\" to print your editable codes.",
        "parameters": [
          {
            "name": "data",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "What the code holds, up to 2000 characters."
            }
          },
          {
            "name": "template",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "A style template id from GET /templates. The code gets that template’s colours, shapes and logo."
            }
          },
          {
            "name": "fg",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Foreground colour as hex, e.g. #111827. Ignored when a template is given."
            }
          },
          {
            "name": "bg",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Background colour as hex. Used together with fg."
            }
          },
          {
            "name": "size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "description": "Width and height in pixels, 64 to 2000. Default 512."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SVG image",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "data: \"data\" is missing or longer than 2000 characters.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "template_not_found: No template with that id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/barcode": {
      "get": {
        "operationId": "renderBarcode",
        "summary": "Render a barcode (SVG)",
        "description": "Draws a retail, shipping or 2D barcode. Check digits are validated; a wrong one returns 400.",
        "parameters": [
          {
            "name": "kind",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "enum": [
                "ean13",
                "isbn",
                "upca",
                "ean8",
                "upce",
                "code128",
                "gs1-128",
                "code39",
                "itf14",
                "datamatrix",
                "gs1-datamatrix"
              ],
              "description": "Barcode type."
            }
          },
          {
            "name": "data",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "description": "The digits or text to encode. GS1 types take (AI)value pairs, e.g. (01)09501101530003(17)261231."
            }
          },
          {
            "name": "fg",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Bar colour as hex."
            }
          },
          {
            "name": "bg",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "description": "Background colour as hex."
            }
          },
          {
            "name": "height",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "description": "Bar height in modules."
            }
          },
          {
            "name": "text",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ],
              "description": "0 hides the human-readable digits under the bars."
            }
          }
        ],
        "responses": {
          "200": {
            "description": "SVG image",
            "content": {
              "image/svg+xml": {
                "schema": {
                  "type": "string"
                }
              }
            }
          },
          "400": {
            "description": "kind: Unknown barcode kind.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/templates": {
      "get": {
        "operationId": "listTemplates",
        "summary": "List style templates",
        "description": "Templates are saved from a code’s look on the Developers page in the app. Pass an id as \"template\" when creating or rendering codes.",
        "parameters": [],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "example": {
                  "data": [
                    {
                      "id": "tpl_8f2k",
                      "name": "Brand",
                      "style": {
                        "fg": "#111827",
                        "bg": "#ffffff",
                        "dots": "rounded"
                      },
                      "created_at": "2026-09-12T08:00:00.000Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "description": "unauthorized: No key, an unknown key, or a revoked key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "pro_required: The workspace is not on Pro.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "rate_limited: More than 60 requests in the last minute with this key.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  }
}