{"openapi":"3.1.0","info":{"title":"qrlia API","version":"1.0.0","description":"REST API for qrlia — dynamic QR codes, designs, scan analytics and webhooks.\n\n**Authentication.** Send `Authorization: Bearer qrc_<prefix>_<rand>` for programmatic access. \nThe dashboard UI uses a cookie session (`qrc_session`) — clients should prefer Bearer keys.\n\n**Scope.** Tenant-scope keys see every company under the tenant. Company-scope keys are pinned \nto one company and cannot reach sibling-company resources or mint other keys.\n\n**Errors.** All non-2xx responses are RFC 7807 `application/problem+json`. Branch on the \nstable `code` field — never on `title` (which is human-readable and may change).\n\n**Auth flows are NOT in this API.** Login, register, password reset etc. live under \n`/api/auth/*` and are intentionally cookie-only.","contact":{"name":"Castle Group","url":"https://castlesoft.eu"},"license":{"name":"Proprietary"}},"servers":[{"url":"https://qrlia.dev.castlesoft.eu","description":"dev"},{"url":"https://qrlia.tst.castlesoft.eu","description":"tst"},{"url":"https://qr.{tenant}.com","description":"prod (per-tenant portal)","variables":{"tenant":{"default":"castlesoft"}}}],"tags":[{"name":"Tenant","description":"Caller's tenant + actor introspection."},{"name":"Companies","description":"Companies under a tenant."},{"name":"Members","description":"Per-company membership management."},{"name":"Templates","description":"Reusable QR templates per qr_type."},{"name":"QR Codes","description":"Dynamic + static QR codes."},{"name":"Designs","description":"Visual presets used by QRs."},{"name":"Webhooks","description":"Event subscriptions (HMAC-signed delivery)."},{"name":"Domains","description":"Custom DNS hostnames + TXT verification."},{"name":"API Keys","description":"API key management (cookie sessions only)."},{"name":"Uploads","description":"Binary asset upload to object storage."}],"components":{"securitySchemes":{"ApiKey":{"type":"http","scheme":"bearer","bearerFormat":"qrc_<prefix>_<rand>","description":"qrlia API key. Mint via POST /api/v1/keys (cookie session) or in /settings. Tenant-scope keys reach every company under the tenant; company-scope keys are pinned to one company."},"Cookie":{"type":"apiKey","in":"cookie","name":"qrc_session","description":"Session cookie minted by /api/auth/login. Used by the dashboard UI; API clients should prefer ApiKey."}},"schemas":{"Problem":{"type":"object","properties":{"type":{"type":"string"},"title":{"type":"string"},"status":{"type":"integer"},"detail":{"type":"string"},"code":{"type":"string"},"instance":{"type":"string"},"requestId":{"type":"string"},"errors":{"type":"array","items":{"type":"object","properties":{"path":{"type":"string"},"message":{"type":"string"}},"required":["path","message"]}}},"required":["type","title","status","code"],"description":"RFC 7807 application/problem+json error response."},"Company":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID of the company."},"tenantId":{"type":"string","format":"uuid"},"slug":{"type":"string","minLength":3,"maxLength":40,"pattern":"^[a-z][a-z0-9-]*[a-z0-9]$","description":"Stable identifier within a tenant. Lowercase, dashes allowed, 3–40 chars."},"name":{"type":"string","minLength":1,"maxLength":120,"description":"Human-readable display name."},"status":{"type":"string","enum":["active","suspended","archived"],"description":"Lifecycle state. `archived` companies are hidden from default listings but kept for analytics joins."},"theme":{"type":"object","properties":{"primaryColor":{"type":"string"},"accentColor":{"type":"string"},"logoUrl":{"type":"string"},"faviconUrl":{"type":"string"},"fontFamily":{"type":"string"},"footerText":{"type":"string"},"defaultCta":{"type":"string"}},"description":"The company's own branding. Its QR landing pages use it over the workspace theme; missing fields fall back to the workspace."},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["id","tenantId","slug","name","status","theme","createdAt","updatedAt"]},"AccessibleCompany":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"UUID of the company."},"slug":{"type":"string","minLength":3,"maxLength":40,"pattern":"^[a-z][a-z0-9-]*[a-z0-9]$","description":"Stable identifier within a tenant. Lowercase, dashes allowed, 3–40 chars."},"name":{"type":"string","minLength":1,"maxLength":120,"description":"Human-readable display name."},"role":{"type":"string","enum":["tenant_admin","company_admin","company_editor","company_viewer"]}},"required":["id","slug","name","role"]},"CompanyProfile":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid","description":"UUID of the company."},"legalName":{"type":["string","null"]},"tagline":{"type":["string","null"]},"addressLine1":{"type":["string","null"]},"addressLine2":{"type":["string","null"]},"city":{"type":["string","null"]},"region":{"type":["string","null"]},"postalCode":{"type":["string","null"]},"country":{"type":["string","null"]},"phone":{"type":["string","null"]},"email":{"type":["string","null"]},"website":{"type":["string","null"]},"logoUrl":{"type":["string","null"]},"logoDarkUrl":{"type":["string","null"]},"social":{"type":"object","additionalProperties":{"type":"string"}},"updatedAt":{"type":"string","format":"date-time"}},"required":["companyId","legalName","tagline","addressLine1","addressLine2","city","region","postalCode","country","phone","email","website","logoUrl","logoDarkUrl","social","updatedAt"]},"Template":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"scope":{"type":"string","enum":["tenant","company"],"description":"`tenant` = shared across the whole tenant. `company` = private to one company."},"tenantId":{"type":"string","format":"uuid"},"companyId":{"type":["string","null"],"format":"uuid"},"qrType":{"type":"string","enum":["url","vcard","profile_card","text","email","phone","sms","whatsapp","wifi","pdf","image","audio","video","app","multilink","menu","feedback","event","dpp","coupon","sepa","paypal","crypto","lead_form"],"description":"Discriminator for QR payload shape."},"name":{"type":"string"},"description":{"type":["string","null"]},"payloadDefaults":{"type":"object","additionalProperties":{}},"designId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","scope","tenantId","companyId","qrType","name","description","payloadDefaults","designId","createdAt"]},"Webhook":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["scan.created","feedback.submitted","qr.created","lead.submitted"],"description":"Event the subscription is interested in."}},"active":{"type":"boolean"},"companyId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"lastFiredAt":{"type":["string","null"],"format":"date-time"},"lastStatus":{"type":["integer","null"]}},"required":["id","url","events","active","companyId","createdAt","lastFiredAt","lastStatus"]},"WebhookCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["scan.created","feedback.submitted","qr.created","lead.submitted"],"description":"Event the subscription is interested in."}},"active":{"type":"boolean"},"companyId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"lastFiredAt":{"type":["string","null"],"format":"date-time"},"lastStatus":{"type":["integer","null"]},"secret":{"type":"string","description":"HMAC signing secret. Shown ONCE — store it now."}},"required":["id","url","events","active","companyId","createdAt","lastFiredAt","lastStatus","secret"]},"Domain":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"host":{"type":"string"},"role":{"type":"string","enum":["portal","redirect","landing"],"description":"`portal` = login + admin UI. `redirect` = short-link host. `landing` = public landing pages."},"tenantId":{"type":"string","format":"uuid"},"companyId":{"type":["string","null"],"format":"uuid"},"isPrimary":{"type":"boolean"},"verifiedAt":{"type":["string","null"],"format":"date-time"},"createdAt":{"type":"string","format":"date-time"},"verification":{"type":"object","properties":{"txtName":{"type":"string"},"txtValue":{"type":"string"}},"required":["txtName","txtValue"]}},"required":["id","host","role","tenantId","companyId","isPrimary","verifiedAt","createdAt","verification"]},"ApiKey":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string","description":"Visible 12-char prefix (e.g. `qrc_abc123_…`). The full key is shown ONCE on creation."},"companyId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"}},"required":["id","name","prefix","companyId","createdAt","lastUsedAt","revokedAt"]},"ApiKeyCreated":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"prefix":{"type":"string","description":"Visible 12-char prefix (e.g. `qrc_abc123_…`). The full key is shown ONCE on creation."},"companyId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"},"lastUsedAt":{"type":["string","null"],"format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"},"key":{"type":"string","description":"The raw API key. Shown ONCE — store securely. Format: `qrc_<prefix>_<rand>`."}},"required":["id","name","prefix","companyId","createdAt","lastUsedAt","revokedAt","key"]},"Member":{"type":"object","properties":{"userId":{"type":"string","format":"uuid"},"email":{"type":"string","format":"email"},"name":{"type":["string","null"]},"role":{"type":"string","enum":["company_admin","company_editor","company_viewer"]},"isTenantAdmin":{"type":"boolean"},"createdAt":{"type":"string","format":"date-time"}},"required":["userId","email","name","role","isTenantAdmin","createdAt"]},"Qr":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"tenantId":{"type":"string","format":"uuid"},"companyId":{"type":"string","format":"uuid"},"type":{"type":"string","enum":["url","vcard","profile_card","text","email","phone","sms","whatsapp","wifi","pdf","image","audio","video","app","multilink","menu","feedback","event","dpp","coupon","sepa","paypal","crypto","lead_form"],"description":"Discriminator for QR payload shape."},"slug":{"type":["string","null"]},"label":{"type":"string"},"payload":{"type":"object","additionalProperties":{}},"designId":{"type":["string","null"],"format":"uuid"},"folderId":{"type":["string","null"],"format":"uuid"},"status":{"type":"string","enum":["active","paused","archived"]},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"},"shortLink":{"type":["string","null"],"format":"uri","description":"The link the printed code encodes (https://<host>/r/<slug>)."},"access":{"type":"object","properties":{"passwordProtected":{"type":"boolean"},"startsAt":{"type":["string","null"]},"expiresAt":{"type":["string","null"]},"maxScans":{"type":["number","null"]},"fallbackUrl":{"type":["string","null"]},"fallbackMessage":{"type":["string","null"]}},"required":["passwordProtected","startsAt","expiresAt","maxScans","fallbackUrl","fallbackMessage"]},"tracking":{"type":"object","properties":{"ga4Id":{"type":"string"},"metaPixelId":{"type":"string"},"gtmId":{"type":"string"},"requestLocation":{"type":"boolean"}}},"totalScans":{"type":"integer","description":"All-time scans; included by list and get."}},"required":["id","tenantId","companyId","type","slug","label","payload","designId","folderId","status","createdAt","updatedAt"]},"Design":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"spec":{"type":"object","additionalProperties":{}},"companyId":{"type":["string","null"],"format":"uuid"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","spec","companyId","createdAt"]},"SsoConnection":{"type":"object","properties":{"issuer":{"type":"string"},"clientId":{"type":"string"},"clientSecretSet":{"type":"boolean","enum":[true]},"allowedDomains":{"type":"array","items":{"type":"string"}},"enabled":{"type":"boolean"},"enforced":{"type":"boolean"},"autoProvision":{"type":"boolean"},"defaultRole":{"type":"string","enum":["advanced","limited"],"description":"Role given to accounts created on first SSO sign-in. Owner is never granted automatically."},"trustUnverifiedEmail":{"type":"boolean"},"buttonLabel":{"type":["string","null"]},"redirectUris":{"type":"array","items":{"type":"string"},"description":"Register every one of these as an allowed redirect / callback URL at the identity provider."},"lastLoginAt":{"type":["string","null"],"format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}},"required":["issuer","clientId","clientSecretSet","allowedDomains","enabled","enforced","autoProvision","defaultRole","trustUnverifiedEmail","buttonLabel","redirectUris","lastLoginAt","updatedAt"]},"ScanAnalytics":{"type":"object","properties":{"range":{"type":"object","properties":{"days":{"type":"number"},"maxDays":{"type":"number"},"requestedDays":{"type":"number"},"since":{"type":"string"},"until":{"type":"string"}},"required":["days","maxDays","requestedDays","since","until"]},"scope":{"type":"object","properties":{"qrId":{"type":["string","null"]},"companyId":{"type":["string","null"]}},"required":["qrId","companyId"]},"totals":{"type":"object","properties":{"scans":{"type":"number"},"uniqueScans":{"type":"number"},"scansToday":{"type":"number"},"activeDays":{"type":"number"},"qrCodes":{"type":"number"},"botScans":{"type":"number"}},"required":["scans","uniqueScans","scansToday","activeDays","qrCodes","botScans"]},"includesBots":{"type":"boolean"},"daily":{"type":"array","items":{"type":"object","properties":{"day":{"type":"string"},"scans":{"type":"number"},"uniqueScans":{"type":"number"}},"required":["day","scans","uniqueScans"]}},"topQrs":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"label":{"type":"string"},"type":{"type":"string"},"scans":{"type":"number"}},"required":["id","label","type","scans"]}},"byCountry":{"type":"array","items":{"type":"object","properties":{"value":{"type":["string","null"]},"scans":{"type":"number"}},"required":["value","scans"]}},"byCity":{"type":"array","items":{"type":"object","properties":{"value":{"type":["string","null"]},"scans":{"type":"number"}},"required":["value","scans"]}},"byOs":{"type":"array","items":{"type":"object","properties":{"value":{"type":["string","null"]},"scans":{"type":"number"}},"required":["value","scans"]}},"byDevice":{"type":"array","items":{"type":"object","properties":{"value":{"type":["string","null"]},"scans":{"type":"number"}},"required":["value","scans"]}},"byReferrer":{"type":"array","items":{"type":"object","properties":{"value":{"type":["string","null"]},"scans":{"type":"number"}},"required":["value","scans"]}},"insights":{"type":"object","properties":{"included":{"type":"boolean"},"upgradeUrl":{"type":["string","null"]}},"required":["included","upgradeUrl"],"description":"False on plans without scan insights (Free): only totals and topQrs are filled."}},"required":["range","scope","totals","includesBots","daily","topQrs","byCountry","byCity","byOs","byDevice","byReferrer","insights"]},"ScanEvent":{"type":"object","properties":{"id":{"type":"string"},"qrId":{"type":"string"},"ts":{"type":"string"},"country":{"type":["string","null"]},"city":{"type":["string","null"]},"os":{"type":["string","null"]},"device":{"type":["string","null"]},"referer":{"type":["string","null"]},"unique24h":{"type":"boolean"},"geoLat":{"type":["number","null"]},"geoLng":{"type":["number","null"]}},"required":["id","qrId","ts","country","city","os","device","referer","unique24h","geoLat","geoLng"]},"Folder":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"name":{"type":"string"},"companyId":{"type":"string","format":"uuid"},"qrCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}},"required":["id","name","companyId","qrCount","createdAt"]}},"parameters":{}},"paths":{"/api/v1/tenants/current":{"get":{"tags":["Tenant"],"summary":"Get the tenant + actor for the current credentials","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Tenant + actor","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":"string"},"name":{"type":"string"},"plan":{"type":"string"},"designerStyleTab":{"type":"boolean"},"designerFrameTab":{"type":"boolean"},"qrFolders":{"type":"boolean"},"theme":{"type":"object","additionalProperties":{}},"actor":{"type":"object","properties":{"kind":{"type":"string","enum":["session","api-tenant","api-company"]},"isTenantAdmin":{"type":"boolean"},"pinnedCompanyId":{"type":["string","null"],"format":"uuid"},"accessibleCompanies":{"type":"array","items":{"$ref":"#/components/schemas/AccessibleCompany"}}},"required":["kind","isTenantAdmin","pinnedCompanyId","accessibleCompanies"]}},"required":["id","slug","name","plan","designerStyleTab","designerFrameTab","qrFolders","theme","actor"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"tags":["Tenant"],"summary":"Rename or re-brand the workspace (admins). The slug/address is not editable.","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"theme":{"type":"object","properties":{"primaryColor":{"anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"string","enum":[""]},{"type":"null"}],"description":"Hex #RRGGBB. Buttons, accents and the landing-page glow."},"accentColor":{"anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"string","enum":[""]},{"type":"null"}],"description":"Hex #RRGGBB. Secondary colour."},"logoUrl":{"anyOf":[{"type":"string","maxLength":1000},{"type":"string","enum":[""]},{"type":"null"}],"description":"An uploaded asset (/uploads/…) or an https URL."},"faviconUrl":{"anyOf":[{"type":"string","maxLength":1000},{"type":"string","enum":[""]},{"type":"null"}],"description":"An uploaded asset (/uploads/…) or an https URL."},"fontFamily":{"anyOf":[{"type":"string","maxLength":80,"pattern":"^[\\w\\s,'\".-]{1,80}$"},{"type":"string","enum":[""]},{"type":"null"}],"description":"CSS font-family list, e.g. \"Georgia, serif\"."},"footerText":{"anyOf":[{"type":"string","maxLength":200},{"type":"string","enum":[""]},{"type":"null"}]},"defaultCta":{"anyOf":[{"type":"string","maxLength":30},{"type":"string","enum":[""]},{"type":"null"}],"description":"Call-to-action on QR frames, e.g. SCAN ME."}}}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/companies":{"get":{"tags":["Companies"],"summary":"List companies the caller can act on","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Accessible companies","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/AccessibleCompany"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Companies"],"summary":"Create a company (tenant-admin only)","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"Human-readable display name."},"slug":{"type":"string","minLength":3,"maxLength":40,"pattern":"^[a-z][a-z0-9-]*[a-z0-9]$","description":"Auto-derived from `name` when omitted (slugified, lowercase)."}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/companies/{id}":{"get":{"tags":["Companies"],"summary":"Get a company","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Company","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"tags":["Companies"],"summary":"Update a company (name, status, branding; the theme is merged field by field, null removes a field)","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120,"description":"Human-readable display name."},"status":{"type":"string","enum":["active","suspended","archived"],"description":"Lifecycle state. `archived` companies are hidden from default listings but kept for analytics joins."},"theme":{"type":"object","properties":{"primaryColor":{"anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"string","enum":[""]},{"type":"null"}],"description":"Hex #RRGGBB. Buttons, accents and the landing-page glow."},"accentColor":{"anyOf":[{"type":"string","pattern":"^#[0-9a-fA-F]{6}$"},{"type":"string","enum":[""]},{"type":"null"}],"description":"Hex #RRGGBB. Secondary colour."},"logoUrl":{"anyOf":[{"type":"string","maxLength":1000},{"type":"string","enum":[""]},{"type":"null"}],"description":"An uploaded asset (/uploads/…) or an https URL."},"faviconUrl":{"anyOf":[{"type":"string","maxLength":1000},{"type":"string","enum":[""]},{"type":"null"}],"description":"An uploaded asset (/uploads/…) or an https URL."},"fontFamily":{"anyOf":[{"type":"string","maxLength":80,"pattern":"^[\\w\\s,'\".-]{1,80}$"},{"type":"string","enum":[""]},{"type":"null"}],"description":"CSS font-family list, e.g. \"Georgia, serif\"."},"footerText":{"anyOf":[{"type":"string","maxLength":200},{"type":"string","enum":[""]},{"type":"null"}]},"defaultCta":{"anyOf":[{"type":"string","maxLength":30},{"type":"string","enum":[""]},{"type":"null"}],"description":"Call-to-action on QR frames, e.g. SCAN ME."}},"description":"Company branding, merged field by field: absent = unchanged, null = removed (the workspace value applies). primaryColor/accentColor are hex #RRGGBB; logoUrl/faviconUrl an upload (/uploads/…) or https URL; fontFamily a CSS font list."}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Company"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Companies"],"summary":"Archive a company (tenant-admin only)","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Archived","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/companies/{id}/profile":{"get":{"tags":["Companies"],"summary":"Get the company profile","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Profile","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyProfile"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"put":{"tags":["Companies"],"summary":"Replace the company profile (company-admin or tenant-admin)","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"legalName":{"type":["string","null"],"maxLength":200},"tagline":{"type":["string","null"],"maxLength":200},"addressLine1":{"type":["string","null"],"maxLength":200},"addressLine2":{"type":["string","null"],"maxLength":200},"city":{"type":["string","null"],"maxLength":120},"region":{"type":["string","null"],"maxLength":120},"postalCode":{"type":["string","null"],"maxLength":40},"country":{"type":["string","null"],"maxLength":80},"phone":{"type":["string","null"],"maxLength":60},"email":{"type":["string","null"],"maxLength":200,"format":"email"},"website":{"type":["string","null"],"maxLength":300,"format":"uri"},"logoUrl":{"type":["string","null"],"maxLength":500},"logoDarkUrl":{"type":["string","null"],"maxLength":500},"social":{"type":"object","additionalProperties":{"type":"string"}}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CompanyProfile"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/companies/{id}/members":{"get":{"tags":["Members"],"summary":"List company members","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Member"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Members"],"summary":"Invite a tenant user into a company","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","maxLength":200,"format":"email"},"role":{"type":"string","enum":["company_admin","company_editor","company_viewer"]}},"required":["email","role"]}}}},"responses":{"201":{"description":"Invited","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"userId":{"type":"string","format":"uuid"},"role":{"type":"string","enum":["company_admin","company_editor","company_viewer"]}},"required":["ok","userId","role"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/companies/{id}/members/{userId}":{"patch":{"tags":["Members"],"summary":"Change a member's role","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"userId","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"role":{"type":"string","enum":["company_admin","company_editor","company_viewer"]}},"required":["role"]}}}},"responses":{"200":{"description":"Ok","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Members"],"summary":"Remove a member from a company","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","format":"uuid"},"required":true,"name":"userId","in":"path"}],"responses":{"200":{"description":"Ok","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/templates":{"get":{"tags":["Templates"],"summary":"List templates visible to the actor","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","enum":["url","vcard","profile_card","text","email","phone","sms","whatsapp","wifi","pdf","image","audio","video","app","multilink","menu","feedback","event","dpp","coupon","sepa","paypal","crypto","lead_form"],"description":"Discriminator for QR payload shape."},"required":false,"description":"Discriminator for QR payload shape.","name":"qrType","in":"query"}],"responses":{"200":{"description":"Templates","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Template"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Templates"],"summary":"Create a template","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"scope":{"type":"string","enum":["tenant","company"],"description":"`tenant` = shared across the whole tenant. `company` = private to one company."},"qrType":{"type":"string","enum":["url","vcard","profile_card","text","email","phone","sms","whatsapp","wifi","pdf","image","audio","video","app","multilink","menu","feedback","event","dpp","coupon","sepa","paypal","crypto","lead_form"],"description":"Discriminator for QR payload shape."},"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":400},"payloadDefaults":{"type":"object","additionalProperties":{},"default":{}},"designId":{"type":"string","format":"uuid"}},"required":["scope","qrType","name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/templates/{id}":{"get":{"tags":["Templates"],"summary":"Get a template","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Template","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"tags":["Templates"],"summary":"Update a template","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":["string","null"],"maxLength":400},"payloadDefaults":{"type":"object","additionalProperties":{}},"designId":{"type":["string","null"],"format":"uuid"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Template"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Templates"],"summary":"Delete a template","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/webhooks":{"get":{"tags":["Webhooks"],"summary":"List webhook subscriptions","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Webhooks","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Webhook"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Webhooks"],"summary":"Subscribe to events. The signing secret is returned ONCE in the response.","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["scan.created","feedback.submitted","qr.created","lead.submitted"],"description":"Event the subscription is interested in."},"minItems":1},"active":{"type":"boolean","default":true},"scope":{"type":"string","enum":["tenant","company"]},"companyId":{"type":"string","format":"uuid"}},"required":["url","events","scope"]}}}},"responses":{"201":{"description":"Created (with secret)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookCreated"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/webhooks/{id}":{"patch":{"tags":["Webhooks"],"summary":"Update a subscription","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string","enum":["scan.created","feedback.submitted","qr.created","lead.submitted"],"description":"Event the subscription is interested in."},"minItems":1},"active":{"type":"boolean"}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Webhook"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Webhooks"],"summary":"Delete a subscription","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/domains":{"get":{"tags":["Domains"],"summary":"List bound hostnames","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Domains","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Domain"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Domains"],"summary":"Bind a host. Hosts are created unverified — call /verify after publishing the TXT challenge.","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"host":{"type":"string","minLength":3,"maxLength":253,"description":"RFC 1035 hostname, lowercase. Trailing dots are stripped."},"role":{"type":"string","enum":["portal","redirect","landing"],"description":"`portal` = login + admin UI. `redirect` = short-link host. `landing` = public landing pages."},"companyId":{"type":["string","null"],"format":"uuid","description":"Pin to a company (white-label). Omit for tenant-wide hosts."}},"required":["host","role"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/domains/{id}":{"patch":{"tags":["Domains"],"summary":"Toggle is_primary or change role","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"isPrimary":{"type":"boolean"},"role":{"type":"string","enum":["portal","redirect","landing"],"description":"`portal` = login + admin UI. `redirect` = short-link host. `landing` = public landing pages."}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Domains"],"summary":"Un-bind a host","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/domains/{id}/verify":{"post":{"tags":["Domains"],"summary":"Re-resolve the TXT challenge and stamp verified_at on success","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Verified","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Domain"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/sso":{"get":{"tags":["Single sign-on"],"summary":"Get the workspace's OpenID Connect SSO connection (workspace admins). The client secret is never returned.","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Connection, or null when none is set up","content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"allOf":[{"$ref":"#/components/schemas/SsoConnection"},{"type":["object","null"]}]}},"required":["connection"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"put":{"tags":["Single sign-on"],"summary":"Create or replace the SSO connection (Enterprise plan). Signed-in workspace admins only; API keys get 403. Enabling it checks the provider's discovery document first.","security":[{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"issuer":{"type":"string","maxLength":500,"format":"uri","description":"OpenID Connect issuer URL, e.g. https://accounts.google.com, https://login.microsoftonline.com/<tenant-id>/v2.0 or https://<org>.okta.com. Must serve /.well-known/openid-configuration."},"clientId":{"type":"string","minLength":1,"maxLength":500},"clientSecret":{"type":"string","minLength":1,"maxLength":2000,"description":"Write-only. Required when creating the connection; omit to keep the stored secret."},"allowedDomains":{"type":"array","items":{"type":"string","minLength":3,"maxLength":253,"description":"RFC 1035 hostname, lowercase. Trailing dots are stripped."},"minItems":1,"maxItems":20,"description":"Email domains the identity provider may sign in, e.g. [\"example.com\"]."},"enabled":{"type":"boolean","default":false,"description":"Show the SSO button and accept SSO sign-ins."},"enforced":{"type":"boolean","default":false,"description":"Turn off password sign-in for everyone except workspace admins (who keep it as a fallback)."},"autoProvision":{"type":"boolean","default":false,"description":"Create an account on first SSO sign-in for allowed-domain users who don't have one yet."},"defaultRole":{"type":"string","enum":["advanced","limited"],"default":"limited","description":"Role given to accounts created on first SSO sign-in. Owner is never granted automatically."},"trustUnverifiedEmail":{"type":"boolean","default":false,"description":"Accept sign-ins whose email the provider doesn't mark verified. Needed for Microsoft Entra ID, which never sends email_verified; only turn on for a provider whose directory you control."},"buttonLabel":{"type":["string","null"],"maxLength":60,"description":"Login button text, e.g. \"Sign in with Okta\". Defaults to \"Sign in with SSO\"."}},"required":["issuer","clientId","allowedDomains"]}}}},"responses":{"200":{"description":"Saved","content":{"application/json":{"schema":{"type":"object","properties":{"connection":{"$ref":"#/components/schemas/SsoConnection"}},"required":["connection"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Single sign-on"],"summary":"Remove the SSO connection. Signed-in workspace admins only.","security":[{"Cookie":[]}],"responses":{"204":{"description":"Removed"},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/sso/test":{"post":{"tags":["Single sign-on"],"summary":"Fetch the identity provider's discovery document with the stored settings","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Result","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"issuer":{"type":["string","null"]},"authorizationEndpoint":{"type":["string","null"]},"error":{"type":["string","null"]}},"required":["ok","issuer","authorizationEndpoint","error"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/keys":{"get":{"tags":["API Keys"],"summary":"List active API keys you can manage (cookie session only)","security":[{"Cookie":[]}],"responses":{"200":{"description":"Keys","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ApiKey"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["API Keys"],"summary":"Mint an API key. The raw key is returned ONCE.","security":[{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80,"description":"Human label for the key — shown in /settings."},"scope":{"type":"string","enum":["tenant","company"],"description":"`tenant` keys see all companies in the tenant. `company` keys are pinned to one company."},"companyId":{"type":"string","format":"uuid","description":"Required when scope='company'; forbidden when scope='tenant'."}},"required":["name","scope"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiKeyCreated"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/keys/{id}":{"delete":{"tags":["API Keys"],"summary":"Revoke an API key","security":[{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Revoked","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/qrs":{"get":{"tags":["QR Codes"],"summary":"List QRs in the active scope, newest first, with short link and all-time scans","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","maxLength":200,"description":"Case-insensitive match on the label."},"required":false,"description":"Case-insensitive match on the label.","name":"search","in":"query"},{"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"string","enum":["root"]}],"description":"Only QRs in this folder; \"root\" = not in any folder."},"required":false,"description":"Only QRs in this folder; \"root\" = not in any folder.","name":"folderId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"companyId","in":"query"},{"schema":{"type":"string","enum":["active","paused","archived"]},"required":false,"name":"status","in":"query"},{"schema":{"type":"string","enum":["url","vcard","profile_card","text","email","phone","sms","whatsapp","wifi","pdf","image","audio","video","app","multilink","menu","feedback","event","dpp","coupon","sepa","paypal","crypto","lead_form"],"description":"Discriminator for QR payload shape."},"required":false,"description":"Discriminator for QR payload shape.","name":"type","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"QRs","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Qr"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["QR Codes"],"summary":"Create a QR. Either supply `templateId` or `type` + per-type fields.","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"type":"object","properties":{"templateId":{"type":"string","format":"uuid"},"label":{"type":"string","minLength":1,"maxLength":200},"payload":{"type":"object","additionalProperties":{}},"designId":{"type":["string","null"],"format":"uuid"},"folderId":{"type":["string","null"],"format":"uuid"},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Company templates default to their own company."}},"required":["templateId"]},{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["url"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"targetUrl":{"type":"string","format":"uri"},"rules":{"type":"array","items":{"type":"object","properties":{"targetUrl":{"type":"string","format":"uri"},"label":{"type":"string","maxLength":80},"countryIn":{"type":"array","items":{"type":"string","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"maxItems":20},"deviceIn":{"type":"array","items":{"type":"string","enum":["mobile","tablet","desktop","bot"]},"maxItems":4},"hourBetween":{"type":"array","prefixItems":[{"type":"integer","minimum":0,"maximum":23},{"type":"integer","minimum":0,"maximum":23}]},"dateAfter":{"type":"string","format":"date-time"},"dateBefore":{"type":"string","format":"date-time"},"languageIn":{"type":"array","items":{"type":"string","pattern":"^[a-z]{2}$"},"maxItems":20},"osIn":{"type":"array","items":{"type":"string","enum":["iOS","iPadOS","Android","Windows","macOS","Linux","ChromeOS"]},"maxItems":7},"scansBelow":{"type":"integer","minimum":1,"maximum":10000000}},"required":["targetUrl"]},"maxItems":10}},"required":["type","label","targetUrl"]},{"type":"object","properties":{"type":{"type":"string","enum":["profile_card"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"profile":{"type":"object","properties":{"displayName":{"type":"string","minLength":1,"maxLength":120},"title":{"type":"string","maxLength":160},"organization":{"type":"string","maxLength":160},"tagline":{"type":"string","maxLength":280},"avatarUrl":{"type":"string","minLength":1},"emails":{"type":"array","items":{"type":"string","format":"email"},"maxItems":6},"phones":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":40},"number":{"type":"string","maxLength":40},"type":{"type":"string","enum":["work","cell","home"],"default":"cell"}},"required":["label","number"]},"maxItems":8},"website":{"type":"string","format":"uri"},"address":{"type":"object","properties":{"street":{"type":"string","maxLength":120},"city":{"type":"string","maxLength":80},"region":{"type":"string","maxLength":80},"postalCode":{"type":"string","maxLength":20},"country":{"type":"string","maxLength":80}}},"socials":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["linkedin","x","instagram","facebook","youtube","github","whatsapp","tiktok","threads","other"]},"url":{"type":"string","format":"uri"},"label":{"type":"string","maxLength":40}},"required":["platform","url"]},"maxItems":10},"note":{"type":"string","maxLength":500}},"required":["displayName"]}},"required":["type","label","profile"]},{"type":"object","properties":{"type":{"type":"string","enum":["multilink"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"multilink":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"tagline":{"type":"string","maxLength":200},"avatarUrl":{"type":"string","format":"uri"},"links":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"url":{"type":"string","format":"uri"},"description":{"type":"string","maxLength":140},"icon":{"type":"string","maxLength":120}},"required":["title","url"]},"minItems":1,"maxItems":20}},"required":["title","links"]}},"required":["type","label","multilink"]},{"type":"object","properties":{"type":{"type":"string","enum":["menu"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"menu":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"tagline":{"type":"string","maxLength":200},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"EUR"},"sections":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","maxLength":240},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":240},"priceCents":{"type":"integer","minimum":0},"currency":{"type":"string","minLength":3,"maxLength":3},"imageUrl":{"type":"string","format":"uri"},"tags":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":8}},"required":["name"]},"minItems":1,"maxItems":60}},"required":["title","items"]},"minItems":1,"maxItems":20}},"required":["title","sections"]}},"required":["type","label","menu"]},{"type":"object","properties":{"type":{"type":"string","enum":["feedback"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"feedback":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"tagline":{"type":"string","maxLength":200},"ratingLabel":{"type":"string","maxLength":60,"default":"How was your experience?"},"thankYou":{"type":"string","maxLength":200,"default":"Thanks — we got it."},"requireContact":{"type":"boolean","default":false},"notifyEmail":{"type":"string","format":"email"},"reviewUrl":{"type":"string","format":"uri"},"reviewMinRating":{"type":"integer","minimum":1,"maximum":5},"reviewLabel":{"type":"string","maxLength":60}},"required":["title"]}},"required":["type","label","feedback"]},{"type":"object","properties":{"type":{"type":"string","enum":["pdf"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"pdf":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":500},"fileUrl":{"type":"string","minLength":1},"filename":{"type":"string","maxLength":200}},"required":["fileUrl"]}},"required":["type","label","pdf"]},{"type":"object","properties":{"type":{"type":"string","enum":["image"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"image":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"caption":{"type":"string","maxLength":500},"fileUrl":{"type":"string","minLength":1},"alt":{"type":"string","maxLength":200}},"required":["fileUrl"]}},"required":["type","label","image"]},{"type":"object","properties":{"type":{"type":"string","enum":["audio"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"audio":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"artist":{"type":"string","maxLength":120},"coverUrl":{"type":"string"},"fileUrl":{"type":"string","minLength":1}},"required":["title","fileUrl"]}},"required":["type","label","audio"]},{"type":"object","properties":{"type":{"type":"string","enum":["video"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"video":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":500},"posterUrl":{"type":"string"},"fileUrl":{"type":"string","minLength":1}},"required":["fileUrl"]}},"required":["type","label","video"]},{"type":"object","properties":{"type":{"type":"string","enum":["app"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"app":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"tagline":{"type":"string","maxLength":200},"iosUrl":{"type":"string","format":"uri"},"androidUrl":{"type":"string","format":"uri"},"fallbackUrl":{"type":"string","format":"uri"},"iconUrl":{"type":"string"}}}},"required":["type","label","app"]},{"type":"object","properties":{"type":{"type":"string","enum":["dpp"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"dpp":{"type":"object","properties":{"productName":{"type":"string","minLength":1,"maxLength":140},"manufacturer":{"type":"string","minLength":1,"maxLength":140},"gtin":{"type":"string","pattern":"^\\d{8}$|^\\d{12}$|^\\d{13}$|^\\d{14}$"},"gs1DigitalLink":{"type":"boolean"},"batch":{"type":"string","maxLength":20},"serial":{"type":"string","maxLength":20},"countryOfOrigin":{"type":"string","minLength":2,"maxLength":2},"materials":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"percentage":{"type":"number","minimum":0,"maximum":100},"origin":{"type":"string","enum":["virgin","recycled","bio-based","reused","unknown"]}},"required":["name"]},"maxItems":20},"weightG":{"type":"number","minimum":0},"recyclable":{"type":"boolean"},"recyclingInstructions":{"type":"string","maxLength":800},"endOfLife":{"type":"string","maxLength":200},"ceMarked":{"type":"boolean"},"hazards":{"type":"string","maxLength":400},"safetyDataSheetUrl":{"type":"string","format":"uri"},"repairContactUrl":{"type":"string","format":"uri"},"warrantyMonths":{"type":"integer","minimum":0,"maximum":600},"carbonFootprintKgCo2e":{"type":"number","minimum":0},"sustainabilityScore":{"type":"string","maxLength":20},"specVersion":{"type":"string","maxLength":20,"default":"ESPR-DPP-v1"}},"required":["productName","manufacturer","gtin"]}},"required":["type","label","dpp"]},{"type":"object","properties":{"type":{"type":"string","enum":["coupon"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"coupon":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"offer":{"type":"string","minLength":1,"maxLength":160},"code":{"type":"string","maxLength":40},"validUntil":{"type":"string","format":"date-time"},"terms":{"type":"string","maxLength":600},"imageUrl":{"type":"string","maxLength":1000},"ctaLabel":{"type":"string","maxLength":40},"ctaUrl":{"type":"string","format":"uri"}},"required":["title","offer"]}},"required":["type","label","coupon"]},{"type":"object","properties":{"type":{"type":"string","enum":["lead_form"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"leadForm":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"intro":{"type":"string","maxLength":400},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,30}$"},"label":{"type":"string","minLength":1,"maxLength":80},"type":{"type":"string","enum":["text","email","phone","textarea","select","checkbox"]},"required":{"type":"boolean"},"options":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"maxItems":20}},"required":["key","label","type"]},"minItems":1,"maxItems":15},"consentText":{"type":"string","minLength":10,"maxLength":500},"submitLabel":{"type":"string","maxLength":40},"thankYou":{"type":"string","maxLength":200},"redirectUrl":{"type":"string","format":"uri"}},"required":["title","fields","consentText"]}},"required":["type","label","leadForm"]},{"type":"object","properties":{"type":{"type":"string","enum":["text","email","phone","sms","whatsapp","wifi","vcard","event","sepa","paypal","crypto"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"payload":{"type":"object","additionalProperties":{},"default":{}}},"required":["type","label"]}]}]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Qr"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/qrs/{id}":{"get":{"tags":["QR Codes"],"summary":"Get a QR","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"QR","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Qr"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"tags":["QR Codes"],"summary":"Update a QR: label, status, content (payload, validated for its type), targetUrl (url type), design or folder. The printed code does not change.","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"label":{"type":"string","minLength":1,"maxLength":200},"status":{"type":"string","enum":["active","paused","archived"],"description":"paused/archived QRs stop redirecting; active resumes."},"targetUrl":{"type":"string","format":"uri","description":"URL QRs only: shorthand for changing payload.targetUrl."},"payload":{"type":"object","additionalProperties":{},"description":"Replace the QR's content. Same shape as the type's create field (e.g. profile, menu, wifi payload); validated against the QR's type. The printed code does not change."},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Qr"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["QR Codes"],"summary":"Delete a QR","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/designs":{"get":{"tags":["Designs"],"summary":"List visible designs","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Designs","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Design"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Designs"],"summary":"Create a design","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"spec":{"type":"object","additionalProperties":{},"description":"Style fields, all optional: foreground and background (hex colour, background may be \"transparent\"); moduleShape square|rounded|dots|extra-rounded|star|sparkle|heart|diamond; eyeShape square|rounded|dot|leaf|petal|petal-out|diamond|flower|shield and eyeInnerShape square|rounded|dot|star|petal|petal-out|diamond|flower|heart (the three corner markers); eyeColor and eyeInnerColor (hex); gradient {type: linear|radial, angle, stops: [{at: 0-1, color}]}; logoUrl (https URL or an /uploads/… path), logoScale up to 0.35, logoShape rect|circle; without a logoUrl the code carries the qrlia mark, and hideLogo: true leaves the centre empty (not on the Free plan, which always shows the mark); errorCorrection L|M|Q|H (H when there is a logo); margin (modules); frame {variant: none|banner|bubble|callout, text up to 30 characters, color, textColor, background}. A brand style is usually foreground = the brand's dark colour, eyeColor = its accent, background = white or its light colour, the company logo in the centre."}},"required":["name","spec"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Design"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/designs/{id}":{"get":{"tags":["Designs"],"summary":"Get a design","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Design","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Design"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Designs"],"summary":"Delete a design","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"tags":["Designs"],"summary":"Rename a design or replace its spec; QRs using it re-render","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"spec":{"type":"object","additionalProperties":{},"description":"Replaces the whole spec. QR codes using this design re-render with it. Style fields, all optional: foreground and background (hex colour, background may be \"transparent\"); moduleShape square|rounded|dots|extra-rounded|star|sparkle|heart|diamond; eyeShape square|rounded|dot|leaf|petal|petal-out|diamond|flower|shield and eyeInnerShape square|rounded|dot|star|petal|petal-out|diamond|flower|heart (the three corner markers); eyeColor and eyeInnerColor (hex); gradient {type: linear|radial, angle, stops: [{at: 0-1, color}]}; logoUrl (https URL or an /uploads/… path), logoScale up to 0.35, logoShape rect|circle; without a logoUrl the code carries the qrlia mark, and hideLogo: true leaves the centre empty (not on the Free plan, which always shows the mark); errorCorrection L|M|Q|H (H when there is a logo); margin (modules); frame {variant: none|banner|bubble|callout, text up to 30 characters, color, textColor, background}. A brand style is usually foreground = the brand's dark colour, eyeColor = its accent, background = white or its light colour, the company logo in the centre."}}}}}},"responses":{"200":{"description":"Updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Design"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/uploads":{"post":{"tags":["Uploads"],"summary":"Upload a binary asset (multipart/form-data)","description":"Stores the file in MinIO under `<tenant-slug>/[c/<company-slug>/]<uuid>.<ext>` and returns a same-origin URL via the /uploads/[...] proxy.","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","description":"Binary file content; field name `file`."}},"required":["file"]}}}},"responses":{"201":{"description":"Uploaded","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string"},"key":{"type":"string"},"bytes":{"type":"integer"},"type":{"type":"string"},"class":{"type":"string"}},"required":["url","key","bytes","type","class"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/qrs/bulk":{"post":{"tags":["QR Codes"],"summary":"Create up to 200 QRs (paid plans). Rows are validated and created one by one; check items[].ok.","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"rows":{"type":"array","items":{"oneOf":[{"type":"object","properties":{"type":{"type":"string","enum":["url"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"targetUrl":{"type":"string","format":"uri"},"rules":{"type":"array","items":{"type":"object","properties":{"targetUrl":{"type":"string","format":"uri"},"label":{"type":"string","maxLength":80},"countryIn":{"type":"array","items":{"type":"string","minLength":2,"maxLength":2,"pattern":"^[A-Z]{2}$"},"maxItems":20},"deviceIn":{"type":"array","items":{"type":"string","enum":["mobile","tablet","desktop","bot"]},"maxItems":4},"hourBetween":{"type":"array","prefixItems":[{"type":"integer","minimum":0,"maximum":23},{"type":"integer","minimum":0,"maximum":23}]},"dateAfter":{"type":"string","format":"date-time"},"dateBefore":{"type":"string","format":"date-time"},"languageIn":{"type":"array","items":{"type":"string","pattern":"^[a-z]{2}$"},"maxItems":20},"osIn":{"type":"array","items":{"type":"string","enum":["iOS","iPadOS","Android","Windows","macOS","Linux","ChromeOS"]},"maxItems":7},"scansBelow":{"type":"integer","minimum":1,"maximum":10000000}},"required":["targetUrl"]},"maxItems":10}},"required":["type","label","targetUrl"]},{"type":"object","properties":{"type":{"type":"string","enum":["profile_card"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"profile":{"type":"object","properties":{"displayName":{"type":"string","minLength":1,"maxLength":120},"title":{"type":"string","maxLength":160},"organization":{"type":"string","maxLength":160},"tagline":{"type":"string","maxLength":280},"avatarUrl":{"type":"string","minLength":1},"emails":{"type":"array","items":{"type":"string","format":"email"},"maxItems":6},"phones":{"type":"array","items":{"type":"object","properties":{"label":{"type":"string","maxLength":40},"number":{"type":"string","maxLength":40},"type":{"type":"string","enum":["work","cell","home"],"default":"cell"}},"required":["label","number"]},"maxItems":8},"website":{"type":"string","format":"uri"},"address":{"type":"object","properties":{"street":{"type":"string","maxLength":120},"city":{"type":"string","maxLength":80},"region":{"type":"string","maxLength":80},"postalCode":{"type":"string","maxLength":20},"country":{"type":"string","maxLength":80}}},"socials":{"type":"array","items":{"type":"object","properties":{"platform":{"type":"string","enum":["linkedin","x","instagram","facebook","youtube","github","whatsapp","tiktok","threads","other"]},"url":{"type":"string","format":"uri"},"label":{"type":"string","maxLength":40}},"required":["platform","url"]},"maxItems":10},"note":{"type":"string","maxLength":500}},"required":["displayName"]}},"required":["type","label","profile"]},{"type":"object","properties":{"type":{"type":"string","enum":["multilink"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"multilink":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"tagline":{"type":"string","maxLength":200},"avatarUrl":{"type":"string","format":"uri"},"links":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"url":{"type":"string","format":"uri"},"description":{"type":"string","maxLength":140},"icon":{"type":"string","maxLength":120}},"required":["title","url"]},"minItems":1,"maxItems":20}},"required":["title","links"]}},"required":["type","label","multilink"]},{"type":"object","properties":{"type":{"type":"string","enum":["menu"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"menu":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"tagline":{"type":"string","maxLength":200},"currency":{"type":"string","minLength":3,"maxLength":3,"default":"EUR"},"sections":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"description":{"type":"string","maxLength":240},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":120},"description":{"type":"string","maxLength":240},"priceCents":{"type":"integer","minimum":0},"currency":{"type":"string","minLength":3,"maxLength":3},"imageUrl":{"type":"string","format":"uri"},"tags":{"type":"array","items":{"type":"string","maxLength":24},"maxItems":8}},"required":["name"]},"minItems":1,"maxItems":60}},"required":["title","items"]},"minItems":1,"maxItems":20}},"required":["title","sections"]}},"required":["type","label","menu"]},{"type":"object","properties":{"type":{"type":"string","enum":["feedback"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"feedback":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"tagline":{"type":"string","maxLength":200},"ratingLabel":{"type":"string","maxLength":60,"default":"How was your experience?"},"thankYou":{"type":"string","maxLength":200,"default":"Thanks — we got it."},"requireContact":{"type":"boolean","default":false},"notifyEmail":{"type":"string","format":"email"},"reviewUrl":{"type":"string","format":"uri"},"reviewMinRating":{"type":"integer","minimum":1,"maximum":5},"reviewLabel":{"type":"string","maxLength":60}},"required":["title"]}},"required":["type","label","feedback"]},{"type":"object","properties":{"type":{"type":"string","enum":["pdf"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"pdf":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":500},"fileUrl":{"type":"string","minLength":1},"filename":{"type":"string","maxLength":200}},"required":["fileUrl"]}},"required":["type","label","pdf"]},{"type":"object","properties":{"type":{"type":"string","enum":["image"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"image":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"caption":{"type":"string","maxLength":500},"fileUrl":{"type":"string","minLength":1},"alt":{"type":"string","maxLength":200}},"required":["fileUrl"]}},"required":["type","label","image"]},{"type":"object","properties":{"type":{"type":"string","enum":["audio"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"audio":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":120},"artist":{"type":"string","maxLength":120},"coverUrl":{"type":"string"},"fileUrl":{"type":"string","minLength":1}},"required":["title","fileUrl"]}},"required":["type","label","audio"]},{"type":"object","properties":{"type":{"type":"string","enum":["video"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"video":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"description":{"type":"string","maxLength":500},"posterUrl":{"type":"string"},"fileUrl":{"type":"string","minLength":1}},"required":["fileUrl"]}},"required":["type","label","video"]},{"type":"object","properties":{"type":{"type":"string","enum":["app"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"app":{"type":"object","properties":{"title":{"type":"string","maxLength":120},"tagline":{"type":"string","maxLength":200},"iosUrl":{"type":"string","format":"uri"},"androidUrl":{"type":"string","format":"uri"},"fallbackUrl":{"type":"string","format":"uri"},"iconUrl":{"type":"string"}}}},"required":["type","label","app"]},{"type":"object","properties":{"type":{"type":"string","enum":["dpp"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"dpp":{"type":"object","properties":{"productName":{"type":"string","minLength":1,"maxLength":140},"manufacturer":{"type":"string","minLength":1,"maxLength":140},"gtin":{"type":"string","pattern":"^\\d{8}$|^\\d{12}$|^\\d{13}$|^\\d{14}$"},"gs1DigitalLink":{"type":"boolean"},"batch":{"type":"string","maxLength":20},"serial":{"type":"string","maxLength":20},"countryOfOrigin":{"type":"string","minLength":2,"maxLength":2},"materials":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":80},"percentage":{"type":"number","minimum":0,"maximum":100},"origin":{"type":"string","enum":["virgin","recycled","bio-based","reused","unknown"]}},"required":["name"]},"maxItems":20},"weightG":{"type":"number","minimum":0},"recyclable":{"type":"boolean"},"recyclingInstructions":{"type":"string","maxLength":800},"endOfLife":{"type":"string","maxLength":200},"ceMarked":{"type":"boolean"},"hazards":{"type":"string","maxLength":400},"safetyDataSheetUrl":{"type":"string","format":"uri"},"repairContactUrl":{"type":"string","format":"uri"},"warrantyMonths":{"type":"integer","minimum":0,"maximum":600},"carbonFootprintKgCo2e":{"type":"number","minimum":0},"sustainabilityScore":{"type":"string","maxLength":20},"specVersion":{"type":"string","maxLength":20,"default":"ESPR-DPP-v1"}},"required":["productName","manufacturer","gtin"]}},"required":["type","label","dpp"]},{"type":"object","properties":{"type":{"type":"string","enum":["coupon"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"coupon":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"offer":{"type":"string","minLength":1,"maxLength":160},"code":{"type":"string","maxLength":40},"validUntil":{"type":"string","format":"date-time"},"terms":{"type":"string","maxLength":600},"imageUrl":{"type":"string","maxLength":1000},"ctaLabel":{"type":"string","maxLength":40},"ctaUrl":{"type":"string","format":"uri"}},"required":["title","offer"]}},"required":["type","label","coupon"]},{"type":"object","properties":{"type":{"type":"string","enum":["lead_form"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"leadForm":{"type":"object","properties":{"title":{"type":"string","minLength":1,"maxLength":80},"intro":{"type":"string","maxLength":400},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,30}$"},"label":{"type":"string","minLength":1,"maxLength":80},"type":{"type":"string","enum":["text","email","phone","textarea","select","checkbox"]},"required":{"type":"boolean"},"options":{"type":"array","items":{"type":"string","minLength":1,"maxLength":60},"maxItems":20}},"required":["key","label","type"]},"minItems":1,"maxItems":15},"consentText":{"type":"string","minLength":10,"maxLength":500},"submitLabel":{"type":"string","maxLength":40},"thankYou":{"type":"string","maxLength":200},"redirectUrl":{"type":"string","format":"uri"}},"required":["title","fields","consentText"]}},"required":["type","label","leadForm"]},{"type":"object","properties":{"type":{"type":"string","enum":["text","email","phone","sms","whatsapp","wifi","vcard","event","sepa","paypal","crypto"]},"label":{"type":"string","minLength":1,"maxLength":200},"designId":{"type":["string","null"],"format":"uuid","description":"Saved design (designs_list) to render this QR with."},"folderId":{"type":["string","null"],"format":"uuid","description":"Folder to file the QR in; null = company root. Plan feature qr_folders."},"companyId":{"type":"string","format":"uuid","description":"Company to create the QR in. Defaults to your pinned/active company, else the workspace's default company."},"access":{"type":"object","properties":{"password":{"type":["string","null"],"minLength":4,"maxLength":128,"description":"Visitors must enter it before the code opens."},"startsAt":{"type":["string","null"],"format":"date-time","description":"Code shows a 'not active yet' message (or fallbackUrl) before this time."},"expiresAt":{"type":["string","null"],"format":"date-time","description":"After this time the code shows its expiry message (or fallbackUrl)."},"maxScans":{"type":["integer","null"],"minimum":1,"maximum":100000000,"description":"Stop after this many scans by people (bots don't count)."},"fallbackUrl":{"type":["string","null"],"format":"uri","description":"Where not-started / expired / used-up codes send visitors."},"fallbackMessage":{"type":["string","null"],"maxLength":200}},"description":"Password, start date, expiry date or scan limit."},"tracking":{"type":"object","properties":{"ga4Id":{"type":["string","null"],"pattern":"^G-[A-Z0-9]{4,15}$"},"metaPixelId":{"type":["string","null"],"pattern":"^\\d{6,20}$"},"gtmId":{"type":["string","null"],"pattern":"^GTM-[A-Z0-9]{4,12}$"},"requestLocation":{"type":["boolean","null"],"description":"Ask visitors (opt-in) to share an approximate location (~1 km)."}},"description":"Analytics tags and opt-in location for the landing page; URL codes show a short consent page first."},"payload":{"type":"object","additionalProperties":{},"default":{}}},"required":["type","label"]}]},"minItems":1,"maxItems":200}},"required":["rows"]}}}},"responses":{"200":{"description":"Per-row result","content":{"application/json":{"schema":{"type":"object","properties":{"total":{"type":"number"},"succeeded":{"type":"number"},"failed":{"type":"number"},"items":{"type":"array","items":{"type":"object","properties":{"ok":{"type":"boolean"},"row":{"type":"number"},"qr":{"$ref":"#/components/schemas/Qr"},"label":{"type":"string"},"error":{"type":"string"}},"required":["ok","row"]}}},"required":["total","succeeded","failed","items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/qrs/{id}/image":{"get":{"tags":["QR Codes"],"summary":"Rendered QR image with its saved design","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string","enum":["png","svg"]},"required":false,"name":"format","in":"query"},{"schema":{"type":"integer","minimum":64,"maximum":4096},"required":false,"name":"size","in":"query"}],"responses":{"200":{"description":"PNG or SVG","content":{"image/png":{"schema":{"type":"string"}},"image/svg+xml":{"schema":{"type":"string"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/qrs/{id}/analytics":{"get":{"tags":["Analytics"],"summary":"Scan analytics for one QR","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":365,"description":"Look-back days; default 30, capped by the plan's analytics history."},"required":false,"description":"Look-back days; default 30, capped by the plan's analytics history.","name":"days","in":"query"},{"schema":{"type":"string","enum":["true","false"],"description":"Include link previews, mail scanners and scripts. Default false."},"required":false,"description":"Include link previews, mail scanners and scripts. Default false.","name":"includeBots","in":"query"}],"responses":{"200":{"description":"Analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanAnalytics"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/qrs/{id}/scans":{"get":{"tags":["Analytics"],"summary":"Scan events for one QR, newest first","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"integer","minimum":1,"maximum":365,"description":"Look-back days; default 30, capped by the plan's analytics history."},"required":false,"description":"Look-back days; default 30, capped by the plan's analytics history.","name":"days","in":"query"},{"schema":{"type":"string","enum":["true","false"],"description":"Include link previews, mail scanners and scripts. Default false."},"required":false,"description":"Include link previews, mail scanners and scripts. Default false.","name":"includeBots","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Scans","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ScanEvent"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/qrs/{id}/feedback":{"get":{"tags":["Analytics"],"summary":"Ratings and comments left on a feedback QR","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200},"required":false,"name":"limit","in":"query"}],"responses":{"200":{"description":"Feedback","content":{"application/json":{"schema":{"type":"object","properties":{"qrId":{"type":"string"},"total":{"type":"number"},"averageRating":{"type":"number"},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"ts":{"type":"string"},"rating":{"type":"number"},"comment":{"type":["string","null"]},"contact":{"type":["string","null"]}},"required":["id","ts","rating","comment","contact"]}},"next":{"type":["string","null"]}},"required":["qrId","total","averageRating","items","next"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/analytics":{"get":{"tags":["Analytics"],"summary":"Scan analytics for the workspace, a company or a QR","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":365,"description":"Look-back days; default 30, capped by the plan's analytics history."},"required":false,"description":"Look-back days; default 30, capped by the plan's analytics history.","name":"days","in":"query"},{"schema":{"type":"string","enum":["true","false"],"description":"Include link previews, mail scanners and scripts. Default false."},"required":false,"description":"Include link previews, mail scanners and scripts. Default false.","name":"includeBots","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"companyId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"qrId","in":"query"}],"responses":{"200":{"description":"Analytics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ScanAnalytics"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/scans":{"get":{"tags":["Analytics"],"summary":"Raw scan events, newest first (no IP data)","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"integer","minimum":1,"maximum":365,"description":"Look-back days; default 30, capped by the plan's analytics history."},"required":false,"description":"Look-back days; default 30, capped by the plan's analytics history.","name":"days","in":"query"},{"schema":{"type":"string","enum":["true","false"],"description":"Include link previews, mail scanners and scripts. Default false."},"required":false,"description":"Include link previews, mail scanners and scripts. Default false.","name":"includeBots","in":"query"},{"schema":{"type":"string"},"required":false,"name":"cursor","in":"query"},{"schema":{"type":"integer","minimum":1,"maximum":200},"required":false,"name":"limit","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"companyId","in":"query"},{"schema":{"type":"string","format":"uuid"},"required":false,"name":"qrId","in":"query"}],"responses":{"200":{"description":"Scans","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ScanEvent"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/folders":{"get":{"tags":["Folders"],"summary":"List QR folders with their QR counts (plan feature qr_folders)","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":false,"name":"companyId","in":"query"}],"responses":{"200":{"description":"Folders","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Folder"}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Folders"],"summary":"Create a folder. Move QRs with PATCH /api/v1/qrs/{id} {folderId}.","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60},"companyId":{"type":"string","format":"uuid","description":"Company the folder belongs to. Defaults to your active/pinned company."}},"required":["name"]}}}},"responses":{"201":{"description":"Created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Folder"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/folders/{id}":{"get":{"tags":["Folders"],"summary":"Get a folder","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Folder","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Folder"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"patch":{"tags":["Folders"],"summary":"Rename a folder","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":60}},"required":["name"]}}}},"responses":{"200":{"description":"Renamed","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Folder"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"delete":{"tags":["Folders"],"summary":"Delete a folder; its QRs move back to the company root","security":[{"ApiKey":[]},{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"id":{"type":"string"},"qrsMovedToRoot":{"type":"number"}},"required":["ok","id","qrsMovedToRoot"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/billing":{"get":{"tags":["Plan & billing"],"summary":"Current plan, status, features and limits, and the plans you can move to","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Billing","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/billing/checkout":{"post":{"tags":["Plan & billing"],"summary":"Hosted checkout link to upgrade from the free plan (workspace admins). A person pays in the browser.","security":[{"ApiKey":[]},{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"planSlug":{"type":"string"},"cadence":{"type":"string","enum":["monthly","annual"]}},"required":["planSlug"]}}}},"responses":{"201":{"description":"Checkout link","content":{"application/json":{"schema":{"type":"object","properties":{"checkoutUrl":{"type":"string","format":"uri"},"planSlug":{"type":"string"},"cadence":{"type":"string"}},"required":["checkoutUrl","planSlug","cadence"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/referrals":{"get":{"tags":["Plan & billing"],"summary":"Referral share link and the signups it brought","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"Referrals","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/me/connected-apps":{"get":{"tags":["Account"],"summary":"OAuth apps the signed-in user connected (not available to API keys)","security":[{"Cookie":[]}],"responses":{"200":{"description":"Connected apps","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","additionalProperties":{}}},"next":{"type":["string","null"]}},"required":["items"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/me/connected-apps/{id}":{"delete":{"tags":["Account"],"summary":"Disconnect an app; its tokens stop working at once","security":[{"Cookie":[]}],"parameters":[{"schema":{"type":"string","format":"uuid"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Disconnected","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"id":{"type":"string"}},"required":["ok","id"]}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/me/export":{"get":{"tags":["Account"],"summary":"GDPR export: every row of the workspace as NDJSON ({table, row} per line). Workspace admins; tenant-scope keys or session.","security":[{"ApiKey":[]},{"Cookie":[]}],"responses":{"200":{"description":"NDJSON stream","content":{"application/x-ndjson":{"schema":{"type":"string"}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}},"/api/v1/companies/active":{"get":{"tags":["Companies"],"summary":"The dashboard's active company (session cookie). API callers pass companyId instead.","security":[{"Cookie":[]}],"responses":{"200":{"description":"Active company","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}},"post":{"tags":["Companies"],"summary":"Switch the dashboard's active company","security":[{"Cookie":[]}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"companyId":{"type":"string","format":"uuid"}},"required":["companyId"]}}}},"responses":{"200":{"description":"Switched","content":{"application/json":{"schema":{"type":"object","additionalProperties":{}}}}},"400":{"description":"Validation failed","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"401":{"description":"Authentication required","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"403":{"description":"Forbidden","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"404":{"description":"Not found","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"409":{"description":"Conflict","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}},"500":{"description":"Internal","content":{"application/problem+json":{"schema":{"$ref":"#/components/schemas/Problem"}}}}}}}},"webhooks":{}}