{"openapi":"3.1.0","info":{"title":"Qex API","version":"1.0.0","description":"Dynamic QR codes: each code encodes a tiny short link on https://qex.me whose destination you can change any time; scans are counted.\n\nAuthenticate with `Authorization: Bearer <token>` — an API key from the dashboard (API & AI) or an OAuth access token.\n\nFree workspaces: 5 active codes, 3 new codes per hour, 5 destination changes per code per day; scans show a 3-second screen before redirecting.\n\n`GET /v1/render` needs no auth and renders a static QR for any text.","contact":{"url":"https://qexqr.com/ai"}},"servers":[{"url":"https://qexqr.com"}],"externalDocs":{"description":"Full reference for LLMs (Markdown)","url":"https://qexqr.com/llms-full.txt"},"security":[{"bearer":[]},{"oauth":["codes"]}],"paths":{"/v1/me":{"get":{"operationId":"getAccount","summary":"Workspace plan, limits and usage","responses":{"200":{"description":"Account","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Account"}}}},"401":{"$ref":"#/components/responses/Error"}}}},"/v1/codes":{"get":{"operationId":"listCodes","summary":"List QR codes (newest first)","responses":{"200":{"description":"Codes","content":{"application/json":{"schema":{"type":"object","properties":{"codes":{"type":"array","items":{"$ref":"#/components/schemas/Code"}}}}}}},"401":{"$ref":"#/components/responses/Error"}}},"post":{"operationId":"createCode","summary":"Create a dynamic QR code","description":"Returns the code with its short link and PNG/SVG image URLs. Show the PNG to the user; the SVG is best for print.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["destination"],"properties":{"destination":{"type":"string","description":"Public http(s) URL. A bare domain gets https:// added.","example":"https://example.com/menu"},"name":{"type":"string","maxLength":80,"example":"Table menu"},"color":{"type":"string","enum":["#121212","#1F4FD6","#0F7A4B","#C23C0A"],"default":"#121212"}}}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/Code"}},"required":["code"]}}}},"401":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/codes/{id}":{"get":{"operationId":"getCode","summary":"Get a QR code","parameters":[{"name":"id","in":"path","required":true,"description":"5-character code ID (case-insensitive).","schema":{"type":"string","pattern":"^[A-Za-z0-9]{5}$"}}],"responses":{"200":{"description":"Code","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/Code"}},"required":["code"]}}}},"401":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"}}},"patch":{"operationId":"updateCode","summary":"Change destination, name, colour or status","description":"Printed codes pick up a new destination within about a minute.","parameters":[{"name":"id","in":"path","required":true,"description":"5-character code ID (case-insensitive).","schema":{"type":"string","pattern":"^[A-Za-z0-9]{5}$"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"destination":{"type":"string"},"name":{"type":"string","maxLength":80},"color":{"type":"string","enum":["#121212","#1F4FD6","#0F7A4B","#C23C0A"]},"status":{"type":"string","enum":["active","paused"]}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"$ref":"#/components/schemas/Code"}},"required":["code"]}}}},"401":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"$ref":"#/components/responses/Error"}}}},"/v1/codes/{id}/stats":{"get":{"operationId":"getCodeStats","summary":"Scan analytics","parameters":[{"name":"id","in":"path","required":true,"description":"5-character code ID (case-insensitive).","schema":{"type":"string","pattern":"^[A-Za-z0-9]{5}$"}},{"name":"days","in":"query","schema":{"type":"integer","enum":[7,30,90],"default":30}}],"responses":{"200":{"description":"Stats","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Stats"}}}},"401":{"$ref":"#/components/responses/Error"},"404":{"$ref":"#/components/responses/Error"}}}},"/v1/render":{"get":{"operationId":"renderQr","summary":"Render a static QR image for any text (no auth)","description":"Not editable and not tracked. Prefer createCode for links that will be printed.","security":[],"parameters":[{"name":"data","in":"query","required":true,"schema":{"type":"string","maxLength":2000}},{"name":"format","in":"query","schema":{"type":"string","enum":["png","svg"],"default":"png"}},{"name":"size","in":"query","description":"PNG width in px (64–2048).","schema":{"type":"integer","default":512}},{"name":"ecc","in":"query","schema":{"type":"string","enum":["L","M","Q","H"],"default":"M"}},{"name":"dark","in":"query","description":"Hex colour without #.","schema":{"type":"string","default":"000000"}},{"name":"light","in":"query","schema":{"type":"string","default":"FFFFFF"}},{"name":"margin","in":"query","description":"Quiet zone in modules.","schema":{"type":"integer","default":4}}],"responses":{"200":{"description":"Image","content":{"image/png":{"schema":{"type":"string","format":"binary"}},"image/svg+xml":{"schema":{"type":"string"}}}},"400":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"}}}}},"components":{"securitySchemes":{"bearer":{"type":"http","scheme":"bearer","description":"API key (qex_sk_…) or OAuth access token."},"oauth":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://qexqr.com/oauth/authorize","tokenUrl":"https://qexqr.com/oauth/token","refreshUrl":"https://qexqr.com/oauth/token","scopes":{"codes":"Create, read and edit QR codes"}}}}},"responses":{"Error":{"description":"Error","content":{"application/json":{"schema":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string"},"message":{"type":"string"}}}}}}},"schemas":{"Code":{"type":"object","properties":{"id":{"type":"string","example":"AB3XK"},"name":{"type":"string"},"destination":{"type":"string"},"status":{"type":"string","enum":["active","paused"]},"color":{"type":"string"},"shortUrl":{"type":"string","example":"https://qex.me/AB3XK"},"qrContent":{"type":"string","description":"Exact text encoded in the QR (uppercase → 21×21 code)."},"image":{"type":"object","properties":{"png":{"type":"string","format":"uri"},"svg":{"type":"string","format":"uri"}}},"dashboardUrl":{"type":"string","format":"uri"},"scanBehavior":{"type":"string","enum":["interstitial_3s","instant_redirect"]},"flagged":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Account":{"type":"object","properties":{"workspaceId":{"type":"string"},"plan":{"type":"string","enum":["free","paid"]},"guest":{"type":"boolean"},"verified":{"type":"boolean"},"scanBehavior":{"type":"string"},"limits":{"type":["object","null"],"description":"null = unlimited"},"usage":{"type":"object","properties":{"activeCodes":{"type":"integer"},"createdLastHour":{"type":"integer"}}},"dashboardUrl":{"type":"string"}}},"Stats":{"type":"object","properties":{"total":{"type":"integer"},"today":{"type":"integer"},"days":{"type":"integer"},"series":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string"},"n":{"type":"integer"}}}},"countries":{"type":"array","items":{"$ref":"#/components/schemas/Row"}},"cities":{"type":"array","items":{"$ref":"#/components/schemas/Row"}},"devices":{"type":"array","items":{"$ref":"#/components/schemas/Row"}},"os":{"type":"array","items":{"$ref":"#/components/schemas/Row"}},"browsers":{"type":"array","items":{"$ref":"#/components/schemas/Row"}},"hours":{"type":"array","items":{"type":"integer"},"description":"24 buckets, scanner-local hour."}}},"Row":{"type":"object","properties":{"key":{"type":"string"},"n":{"type":"integer"}}}}}}