{"openapi":"3.1.0","info":{"title":"QRnaly Public REST API","version":"1.0.0","description":"Official REST API for QRnaly.com: enterprise QR code lifecycle management, campaign folders, design templates, hosted campaign assets, and scan telemetry.\n\nCommercial Model & Quotas:\n- Free: 1 test dynamic QR (14-day trial), unlimited static QRs, 10 MB storage (max 1 file with 30-day retention), 14-day API trial with 50 requests workspace-wide at 30 req/min.\n- Pro (₹399/mo): 50 active dynamic QRs, 100 monthly dynamic destination updates, 1 GB storage (25 MB PDF / 10 MB Image) with indefinite retention, 30 req/min API rate limit.\n- Business (₹999/mo): 500 active dynamic QRs, 1,000 monthly dynamic destination updates, 10 GB storage (100 MB PDF / 25 MB Image) with indefinite retention, 60 req/min API rate limit.\n\nAPI Governance & Trial Semantics:\n- Free API trial provides 50 total requests per workspace over a 14-day trial window from registration.\n- Rate limit during trial is 30 requests/minute.\n- Only successfully authenticated and rate-limit cleared requests count towards the 50-request limit.\n- HTTP 429 (Rate Limit Exceeded) and HTTP 403 (Insufficient Scope) do NOT consume trial requests.\n- Client validation errors (HTTP 4xx) on authenticated requests DO count.\n- Once 50 requests are exhausted, subsequent calls receive HTTP 403 (TRIAL_API_LIMIT_EXCEEDED).\n- Once the 14-day trial expires, calls receive HTTP 403 (API_ACCESS_REQUIRES_PAID_PLAN).","contact":{"name":"QRnaly API Support","url":"https://qrnaly.com/support","email":"support@qrnaly.com"}},"servers":[{"url":"https://qrnaly.com/api/v1","description":"Production API Gateway"}],"paths":{"/me":{"get":{"summary":"Get Caller Identity & Workspace","description":"Returns the workspace identity, role, and active scopes associated with the API key.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"responses":{"200":{"description":"Authenticated workspace details"},"401":{"description":"Missing or invalid API key"}}}},"/usage":{"get":{"summary":"Get Quotas & QR Credit Balance","description":"Returns the current workspace usage, remaining dynamic updates, active dynamic limits, and rate limits.","security":[{"bearerAuth":[]},{"apiKeyHeader":[]}],"responses":{"200":{"description":"Workspace usage and credit balance"}}}},"/qr":{"get":{"summary":"List Workspace QR Codes","description":"Returns a paginated list of QR codes for the workspace. Supports filtering by folderId.","security":[{"bearerAuth":["qr:read"]},{"apiKeyHeader":["qr:read"]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20,"maximum":100}},{"name":"folderId","in":"query","schema":{"type":"string"}}],"responses":{"200":{"description":"Paginated list of QR codes"}}},"post":{"summary":"Create QR Code","description":"Generates a new static or dynamic QR code with atomic credit allocation. Supports Idempotency-Key.","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"required":false}],"responses":{"201":{"description":"QR Code created successfully"},"400":{"description":"Bad Request"},"402":{"description":"Insufficient QR Credits"},"403":{"description":"Active dynamic limit reached"}}}},"/qr/{id}":{"get":{"summary":"Get QR Code by ID","security":[{"bearerAuth":["qr:read"]},{"apiKeyHeader":["qr:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"QR code details"},"404":{"description":"Not found"}}},"patch":{"summary":"Update QR Code","description":"Updates destination URL, folder assignment, design styling, or name without changing the printed code.","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"QR code updated"}}},"delete":{"summary":"Delete QR Code","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"QR code deleted"}}}},"/qr/{id}/pause":{"post":{"summary":"Pause QR Code","description":"Temporarily halts redirects for a dynamic QR code and records a state transition.","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"required":false}],"responses":{"200":{"description":"QR code paused successfully"}}}},"/qr/{id}/resume":{"post":{"summary":"Resume QR Code","description":"Reactivates redirects for a previously paused dynamic QR code.","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"required":false}],"responses":{"200":{"description":"QR code resumed successfully"}}}},"/qr/{id}/duplicate":{"post":{"summary":"Duplicate QR Code","description":"Creates an exact clone of a QR code with independent slug and atomic credit deduction.","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"required":false}],"responses":{"201":{"description":"QR code duplicated successfully"},"402":{"description":"Insufficient QR Credits"},"403":{"description":"Active dynamic limit reached"}}}},"/qr/{id}/history":{"get":{"summary":"List Destination History","description":"Returns the immutable destination change audit log for a dynamic QR code.","security":[{"bearerAuth":["qr:read"]},{"apiKeyHeader":["qr:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"Destination history entries"}}}},"/qr/{id}/history/restore":{"post":{"summary":"Restore Destination History Version","description":"Restores a historical destination URL while appending an audit entry and validating destination safety.","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"required":false}],"responses":{"200":{"description":"Destination URL restored successfully"}}}},"/folders":{"get":{"summary":"List Campaign Folders","description":"Returns paginated organizational folders for the workspace.","security":[{"bearerAuth":["folders:read"]},{"apiKeyHeader":["folders:read"]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"List of folders"}}},"post":{"summary":"Create Campaign Folder","description":"Creates a new organizational folder.","security":[{"bearerAuth":["folders:write"]},{"apiKeyHeader":["folders:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"required":false}],"responses":{"201":{"description":"Folder created successfully"}}}},"/folders/{id}":{"get":{"summary":"Get Folder by ID","security":[{"bearerAuth":["folders:read"]},{"apiKeyHeader":["folders:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Folder details"}}},"patch":{"summary":"Update Folder","security":[{"bearerAuth":["folders:write"]},{"apiKeyHeader":["folders:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Folder updated"}}},"delete":{"summary":"Delete Folder","description":"Deletes the folder and disassociates assigned QR codes (unassigned).","security":[{"bearerAuth":["folders:write"]},{"apiKeyHeader":["folders:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Folder deleted and QRs unassigned"}}}},"/templates":{"get":{"summary":"List Design Templates","description":"Returns reusable visual design templates for the workspace.","security":[{"bearerAuth":["templates:read"]},{"apiKeyHeader":["templates:read"]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"List of templates"}}},"post":{"summary":"Create Design Template","description":"Creates a new reusable visual design template decoupled from destination payloads.","security":[{"bearerAuth":["templates:write"]},{"apiKeyHeader":["templates:write"]}],"parameters":[{"name":"Idempotency-Key","in":"header","schema":{"type":"string"},"required":false}],"responses":{"201":{"description":"Template created successfully"}}}},"/templates/{id}":{"get":{"summary":"Get Design Template by ID","security":[{"bearerAuth":["templates:read"]},{"apiKeyHeader":["templates:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template details"}}},"patch":{"summary":"Update Design Template","security":[{"bearerAuth":["templates:write"]},{"apiKeyHeader":["templates:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template updated"}}},"delete":{"summary":"Delete Design Template","security":[{"bearerAuth":["templates:write"]},{"apiKeyHeader":["templates:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Template deleted"}}}},"/catalogs":{"get":{"summary":"List Workspace Digital Catalogues","description":"Returns paginated digital catalogues/menus for the workspace with section counts, item counts, and linked QR metadata.","security":[{"bearerAuth":["catalogs:read"]},{"apiKeyHeader":["catalogs:read"]}],"parameters":[{"name":"template","in":"query","schema":{"type":"string","enum":["restaurant","bakery","retail","services","real_estate","courses","products","packages","events","custom"]}},{"name":"status","in":"query","schema":{"type":"string","enum":["draft","published","archived"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":50}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Paginated list of digital catalogues","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"catalogs":{"type":"array","items":{"$ref":"#/components/schemas/Catalog"}},"total":{"type":"integer"}}}}}}}},"post":{"summary":"Create Digital Catalogue","description":"Creates a new digital catalogue or menu with vertical-specific template configuration, branding, contact CTAs, and themes.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","example":"Artisan Bakery Menu"},"subtitle":{"type":"string","example":"Fresh sourdough, cakes, and pastries daily"},"businessName":{"type":"string","example":"Sweet Crust Bakery"},"template":{"type":"string","enum":["restaurant","bakery","retail","services","real_estate","courses","products","packages","events","custom"],"default":"restaurant"},"slug":{"type":"string","example":"sweet-crust-bakery"},"currency":{"type":"string","default":"INR","example":"INR"},"logoUrl":{"type":"string","example":"/i/logo_sweetcrust.png"},"coverImageUrl":{"type":"string","example":"/i/cover_sweetcrust.jpg"},"address":{"type":"string","example":"Shop 4, Bandra West, Mumbai"},"phone":{"type":"string","example":"+919876543210"},"whatsapp":{"type":"string","example":"919876543210"},"contactCtaLabel":{"type":"string","example":"Order via WhatsApp"},"openingHours":{"type":"string","example":"Mon-Sun: 8:00 AM - 10:00 PM"},"theme":{"type":"object"},"settings":{"type":"object"}}}}}},"responses":{"201":{"description":"Catalogue created successfully"},"400":{"description":"Validation error"}}}},"/catalogs/{id}":{"get":{"summary":"Get Catalogue Details with Sections & Items","description":"Returns the full hierarchical catalogue object including categories/sections, items, variants, add-ons, and dynamic QR link.","security":[{"bearerAuth":["catalogs:read"]},{"apiKeyHeader":["catalogs:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Full catalogue object","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"catalog":{"$ref":"#/components/schemas/CatalogDetails"}}}}}},"404":{"description":"Catalogue not found"}}},"patch":{"summary":"Update Catalogue Metadata & Settings","description":"Updates catalogue title, branding, theme, and settings. Published slugs are immutable unless unpublished.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalogue updated"}}},"delete":{"summary":"Delete Catalogue","description":"Permanently deletes catalogue, associated sections, items, and disassociates linked QR codes.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalogue deleted"}}}},"/catalogs/{id}/publish":{"post":{"summary":"Publish Digital Catalogue","description":"Transitions catalogue from draft to published status and binds public routing at qrnaly.com/menu/{slug} or /catalog/{slug}.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalogue published"}}}},"/catalogs/{id}/unpublish":{"post":{"summary":"Unpublish Digital Catalogue","description":"Reverts catalogue to draft status, taking it offline from public access.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Catalogue unpublished"}}}},"/catalogs/{id}/duplicate":{"post":{"summary":"Duplicate Digital Catalogue","description":"Deep-clones the catalogue, all categories/sections, and items into an independent draft copy.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"201":{"description":"Catalogue duplicated"}}}},"/catalogs/{id}/sections":{"get":{"summary":"List Catalogue Sections / Categories","description":"Returns all sections/categories defined within the specified catalogue.","security":[{"bearerAuth":["catalogs:read"]},{"apiKeyHeader":["catalogs:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of sections","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"sections":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"sortOrder":{"type":"integer"}}}}}}}}},"404":{"description":"Catalogue not found"}}},"post":{"summary":"Create Catalogue Section / Category","description":"Creates an organizational category or section (e.g. Signature Cakes, Appetizers, Consulting Packages).","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","example":"Signature Cakes"},"description":{"type":"string","example":"Handcrafted daily using organic ingredients"},"sortOrder":{"type":"integer","default":0}}}}}},"responses":{"201":{"description":"Section created"}}}},"/catalogs/{id}/items":{"get":{"summary":"List All Items in Catalogue","security":[{"bearerAuth":["catalogs:read"]},{"apiKeyHeader":["catalogs:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"List of catalogue items"}}},"post":{"summary":"Create Catalogue Item with Variants & Add-ons","description":"Creates a catalogue item. Supports fixed/starting pricing, multi-variants with server-generated canonical IDs (var_<uuid>), customizable add-ons (add_<uuid>), and availability flags.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","sectionId"],"properties":{"name":{"type":"string","example":"Belgian Chocolate Truffle Cake"},"sectionId":{"type":"string","example":"sec_12345"},"description":{"type":"string","example":"Rich 55% dark chocolate ganache layered with moist sponge."},"price":{"type":"number","example":450},"priceLabel":{"type":"string","example":"Starting from"},"pricingType":{"type":"string","enum":["fixed","starting_from","free","on_request","custom","hidden"],"default":"fixed"},"badge":{"type":"string","example":"Bestseller"},"imageUrl":{"type":"string","example":"/i/belgian_truffle.jpg"},"isAvailable":{"type":"boolean","default":true},"sortOrder":{"type":"integer","default":0},"metadata":{"$ref":"#/components/schemas/CatalogItemMetadata"}}}}}},"responses":{"201":{"description":"Item created successfully"}}}},"/catalogs/{id}/items/{itemId}":{"patch":{"summary":"Update Catalogue Item","description":"Updates item name, price, badge, description, variants, or add-ons. Preserves existing canonical IDs.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Item updated"}}},"delete":{"summary":"Delete Catalogue Item","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Item deleted"}}}},"/catalogs/{id}/items/{itemId}/toggle-availability":{"post":{"summary":"Toggle Item Availability (In-Stock / Sold-Out)","description":"Instant 1-click toggle for kitchen and storefront availability without editing the entire item payload.","security":[{"bearerAuth":["catalogs:write"]},{"apiKeyHeader":["catalogs:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"itemId","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"isAvailable":{"type":"boolean","description":"Explicit availability state. If omitted, toggles current value."}}}}}},"responses":{"200":{"description":"Availability state updated"}}}},"/social-profiles":{"get":{"summary":"List Social Profiles","description":"Returns all social link landing pages and bio profiles for the workspace.","security":[{"bearerAuth":["qr:read"]},{"apiKeyHeader":["qr:read"]}],"responses":{"200":{"description":"List of social profiles"}}},"post":{"summary":"Create Social Profile","description":"Creates a mobile-friendly link-in-bio social profile page.","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["profileName"],"properties":{"profileName":{"type":"string","example":"Sarah Jenkins Design"},"bio":{"type":"string","example":"Brand & Graphic Designer based in London."},"avatarUrl":{"type":"string","example":"https://example.com/avatar.jpg"},"links":{"type":"array","items":{"type":"object"}}}}}}},"responses":{"201":{"description":"Social profile created"}}}},"/social-profiles/{id}":{"get":{"summary":"Get Social Profile","security":[{"bearerAuth":["qr:read"]},{"apiKeyHeader":["qr:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Social profile details"},"404":{"description":"Not found"}}},"patch":{"summary":"Update Social Profile","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Social profile updated"}}},"delete":{"summary":"Delete Social Profile","security":[{"bearerAuth":["qr:write"]},{"apiKeyHeader":["qr:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Social profile deleted"}}}},"/analytics/workspace":{"get":{"summary":"Get Workspace Aggregate Analytics","description":"Returns workspace-level scan trends, unique scanners, top QRs, and demographic breakdowns (7d, 30d, 90d).","security":[{"bearerAuth":["analytics:read"]},{"apiKeyHeader":["analytics:read"]}],"parameters":[{"name":"days","in":"query","schema":{"type":"integer","enum":[7,30,90],"default":30}},{"name":"period","in":"query","schema":{"type":"string","enum":["7d","30d","90d"]}}],"responses":{"200":{"description":"Workspace aggregate analytics"}}}},"/analytics/folders/{id}":{"get":{"summary":"Get Folder Aggregate Analytics","description":"Returns aggregate analytics for all QR codes assigned to a specific folder.","security":[{"bearerAuth":["analytics:read"]},{"apiKeyHeader":["analytics:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"days","in":"query","schema":{"type":"integer","enum":[7,30,90],"default":30}}],"responses":{"200":{"description":"Folder aggregate analytics"}}}},"/analytics/{id}":{"get":{"summary":"Get QR Scan Analytics","description":"Returns 30-day time-series telemetry, device breakdown, OS, and city rollups for a single QR code.","security":[{"bearerAuth":["analytics:read"]},{"apiKeyHeader":["analytics:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Scan telemetry metrics"}}}},"/analytics/{id}/export":{"get":{"summary":"Export Privacy-Preserving Raw Scan Telemetry","description":"Exports sanitized raw scan logs (timestamp, city, country, browser, os, device, referrer). Zero raw IPs or hashes.","security":[{"bearerAuth":["analytics:read"]},{"apiKeyHeader":["analytics:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"}},{"name":"limit","in":"query","schema":{"type":"integer","default":1000,"maximum":5000}}],"responses":{"200":{"description":"Exported telemetry in JSON or CSV format"}}}},"/documents":{"get":{"summary":"List Hosted Documents","security":[{"bearerAuth":["documents:read"]},{"apiKeyHeader":["documents:read"]}],"parameters":[{"name":"page","in":"query","schema":{"type":"integer","default":1}},{"name":"limit","in":"query","schema":{"type":"integer","default":20}}],"responses":{"200":{"description":"List of documents"}}},"post":{"summary":"Upload Hosted Document","description":"Registers or uploads a PDF or image file. Deducts 2 QR Credits.","security":[{"bearerAuth":["documents:write"]},{"apiKeyHeader":["documents:write"]}],"responses":{"200":{"description":"Document registered"}}}},"/documents/{id}":{"get":{"summary":"Get Hosted Document by ID","security":[{"bearerAuth":["documents:read"]},{"apiKeyHeader":["documents:read"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document details"}}},"delete":{"summary":"Delete Hosted Document","security":[{"bearerAuth":["documents:write"]},{"apiKeyHeader":["documents:write"]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Document deleted"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"API_KEY (qrs_live_...)","description":"Standard Bearer Token Header"},"apiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API Key Header"}},"schemas":{"Catalog":{"type":"object","properties":{"id":{"type":"string","example":"cat_01j8m4..."},"title":{"type":"string","example":"Artisan Bakery Menu"},"subtitle":{"type":"string","example":"Fresh sourdough, cakes, and pastries daily"},"businessName":{"type":"string","example":"Sweet Crust Bakery"},"slug":{"type":"string","example":"sweet-crust-bakery"},"template":{"type":"string","enum":["restaurant","bakery","retail","services","real_estate","courses","products","packages","events","custom"]},"status":{"type":"string","enum":["draft","published","archived"]},"currency":{"type":"string","example":"INR"},"logoUrl":{"type":"string","nullable":true},"coverImageUrl":{"type":"string","nullable":true},"sectionCount":{"type":"integer","example":4},"itemCount":{"type":"integer","example":28},"qrSlug":{"type":"string","nullable":true},"qrShortUrl":{"type":"string","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"CatalogDetails":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"subtitle":{"type":"string","nullable":true},"businessName":{"type":"string"},"slug":{"type":"string"},"template":{"type":"string"},"status":{"type":"string"},"currency":{"type":"string"},"theme":{"type":"object"},"settings":{"type":"object"},"sections":{"type":"array","items":{"$ref":"#/components/schemas/CatalogSection"}},"qr_slug":{"type":"string","nullable":true},"qr_short_url":{"type":"string","nullable":true}}},"CatalogSection":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"Signature Cakes"},"description":{"type":"string","nullable":true},"sortOrder":{"type":"integer"},"items":{"type":"array","items":{"$ref":"#/components/schemas/CatalogItem"}}}},"CatalogItem":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string","example":"Belgian Chocolate Truffle Cake"},"description":{"type":"string","nullable":true},"price":{"type":"number","nullable":true,"example":450},"priceLabel":{"type":"string","nullable":true,"example":"Starting from"},"pricingType":{"type":"string","enum":["fixed","starting_from","free","on_request","custom","hidden"]},"badge":{"type":"string","nullable":true,"example":"Bestseller"},"imageUrl":{"type":"string","nullable":true},"isAvailable":{"type":"boolean","example":true},"sortOrder":{"type":"integer","example":0},"metadata":{"$ref":"#/components/schemas/CatalogItemMetadata"}}},"CatalogItemMetadata":{"type":"object","description":"Vertical-specific item metadata with schema versioning and server-generated canonical IDs for variants and add-ons.","properties":{"schemaVersion":{"type":"integer","default":1},"variants":{"type":"array","items":{"$ref":"#/components/schemas/CatalogVariant"}},"addOns":{"type":"array","items":{"$ref":"#/components/schemas/CatalogAddOn"}},"dietary":{"type":"array","items":{"type":"string"},"example":["Eggless","Gluten-Free"]},"attributes":{"type":"object","example":{"weight":"500g","duration":"60 min","preparationTime":"20 min"}}}},"CatalogVariant":{"type":"object","properties":{"id":{"type":"string","pattern":"^var_[a-zA-Z0-9_-]+$","example":"var_9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d"},"name":{"type":"string","example":"500g"},"price":{"type":"number","example":450},"isDefault":{"type":"boolean","default":false},"isAvailable":{"type":"boolean","default":true}}},"CatalogAddOn":{"type":"object","properties":{"id":{"type":"string","pattern":"^add_[a-zA-Z0-9_-]+$","example":"add_4a2c09fb-6d88-4f15-a7b2-8f92de1c09ab"},"name":{"type":"string","example":"Custom Acrylic Cake Topper"},"price":{"type":"number","example":120},"maxQuantity":{"type":"integer","default":1},"isAvailable":{"type":"boolean","default":true}}}}},"security":[{"bearerAuth":[]},{"apiKeyHeader":[]}]}