[{"data":1,"prerenderedAt":1890},["ShallowReactive",2],{"navigation":3,"\u002Fbooki-documentation\u002Fguides\u002Fguides-multi-tenancy":303,"\u002Fbooki-documentation\u002Fguides\u002Fguides-multi-tenancy-surround":1885},[4,55,105],{"title":5,"icon":6,"path":7,"stem":8,"children":9,"page":54},"Nuxt Guide","i-lucide-layout","\u002Fnuxt-guide","1.nuxt-guide",[10,14,19,24,29,34,39,44,49],{"title":11,"path":12,"stem":13,"icon":6},"Overview","\u002Fnuxt-guide\u002Foverview","1.nuxt-guide\u002F1.overview",{"title":15,"path":16,"stem":17,"icon":18},"Folder Structure","\u002Fnuxt-guide\u002Ffolder-structure","1.nuxt-guide\u002F2.folder-structure","i-lucide-folder-tree",{"title":20,"path":21,"stem":22,"icon":23},"Components","\u002Fnuxt-guide\u002Fcomponents","1.nuxt-guide\u002F3.components","i-lucide-component",{"title":25,"path":26,"stem":27,"icon":28},"Composables","\u002Fnuxt-guide\u002Fcomposables","1.nuxt-guide\u002F4.composables","i-lucide-puzzle",{"title":30,"path":31,"stem":32,"icon":33},"Pages & Routing","\u002Fnuxt-guide\u002Fpages-routing","1.nuxt-guide\u002F5.pages-routing","i-lucide-file-text",{"title":35,"path":36,"stem":37,"icon":38},"Middleware","\u002Fnuxt-guide\u002Fmiddleware","1.nuxt-guide\u002F6.middleware","i-lucide-shield-check",{"title":40,"path":41,"stem":42,"icon":43},"Plugins","\u002Fnuxt-guide\u002Fplugins","1.nuxt-guide\u002F7.plugins","i-lucide-plug",{"title":45,"path":46,"stem":47,"icon":48},"State Management","\u002Fnuxt-guide\u002Fstate-management","1.nuxt-guide\u002F8.state-management","i-lucide-database",{"title":50,"path":51,"stem":52,"icon":53},"TypeScript","\u002Fnuxt-guide\u002Ftypescript","1.nuxt-guide\u002F9.typescript","i-lucide-braces",false,{"title":56,"icon":57,"path":58,"stem":59,"children":60,"page":54},"Node \u002F Express Guide","i-lucide-server","\u002Fnode-express-guide","2.node-express-guide",[61,64,69,72,77,82,86,91,96,100],{"title":11,"path":62,"stem":63,"icon":57},"\u002Fnode-express-guide\u002Foverview","2.node-express-guide\u002F1.overview",{"title":65,"path":66,"stem":67,"icon":68},"Error Handling","\u002Fnode-express-guide\u002Ferror-handling","2.node-express-guide\u002F10.error-handling","i-lucide-alert-triangle",{"title":15,"path":70,"stem":71,"icon":18},"\u002Fnode-express-guide\u002Ffolder-structure","2.node-express-guide\u002F2.folder-structure",{"title":73,"path":74,"stem":75,"icon":76},"Controllers","\u002Fnode-express-guide\u002Fcontrollers","2.node-express-guide\u002F3.controllers","i-lucide-cpu",{"title":78,"path":79,"stem":80,"icon":81},"Services","\u002Fnode-express-guide\u002Fservices","2.node-express-guide\u002F4.services","i-lucide-workflow",{"title":83,"path":84,"stem":85,"icon":48},"Repositories","\u002Fnode-express-guide\u002Frepositories","2.node-express-guide\u002F5.repositories",{"title":87,"path":88,"stem":89,"icon":90},"Models","\u002Fnode-express-guide\u002Fmodels","2.node-express-guide\u002F6.models","i-lucide-boxes",{"title":92,"path":93,"stem":94,"icon":95},"Routes","\u002Fnode-express-guide\u002Froutes","2.node-express-guide\u002F7.routes","i-lucide-route",{"title":35,"path":97,"stem":98,"icon":99},"\u002Fnode-express-guide\u002Fmiddleware","2.node-express-guide\u002F8.middleware","i-lucide-shield",{"title":101,"path":102,"stem":103,"icon":104},"Validation","\u002Fnode-express-guide\u002Fvalidation","2.node-express-guide\u002F9.validation","i-lucide-check-circle",{"title":106,"icon":107,"path":108,"stem":109,"children":110,"page":54},"Booki Documentation","i-lucide-book-open","\u002Fbooki-documentation","3.booki-documentation",[111,115,120,125,130,229,244,257],{"title":112,"path":113,"stem":114,"icon":107},"Project Overview","\u002Fbooki-documentation\u002Foverview","3.booki-documentation\u002F1.overview",{"title":116,"path":117,"stem":118,"icon":119},"Installation","\u002Fbooki-documentation\u002F1.installation","3.booki-documentation\u002F2.1.installation","i-lucide-download",{"title":121,"path":122,"stem":123,"icon":124},"Development Overview","\u002Fbooki-documentation\u002F2.architecture","3.booki-documentation\u002F2.2.architecture","i-lucide-layers",{"title":126,"path":127,"stem":128,"icon":129},"Local Development","\u002Fbooki-documentation\u002F3.local-development","3.booki-documentation\u002F2.3.local-development","i-lucide-monitor",{"title":131,"icon":57,"path":132,"stem":133,"children":134,"page":54},"API","\u002Fbooki-documentation\u002Fapi","3.booki-documentation\u002F3.api",[135,139,144,149,154,159,163,168,173,178,183,188,192,197,202,206,211,216,220,224],{"title":136,"path":137,"stem":138,"icon":57},"Booki API Reference","\u002Fbooki-documentation\u002Fapi\u002Fbooki-api","3.booki-documentation\u002F3.api\u002F1.booki-api",{"title":140,"path":141,"stem":142,"icon":143},"Auth - Login & Refresh","\u002Fbooki-documentation\u002Fapi\u002Fauth","3.booki-documentation\u002F3.api\u002F2.auth","i-lucide-key",{"title":145,"path":146,"stem":147,"icon":148},"Auth - Customer Registration","\u002Fbooki-documentation\u002Fapi\u002Fauth-customer-register","3.booki-documentation\u002F3.api\u002F2.auth-customer-register","i-lucide-user-check",{"title":150,"path":151,"stem":152,"icon":153},"Auth - Owner Registration","\u002Fbooki-documentation\u002Fapi\u002Fauth-owner-register","3.booki-documentation\u002F3.api\u002F2.auth-owner-register","i-lucide-user-plus",{"title":155,"path":156,"stem":157,"icon":158},"Bookings","\u002Fbooki-documentation\u002Fapi\u002Fbookings","3.booki-documentation\u002F3.api\u002F3.bookings","i-lucide-calendar-check",{"title":160,"path":161,"stem":162,"icon":158},"Bookings - Authenticated","\u002Fbooki-documentation\u002Fapi\u002Fbookings-auth","3.booki-documentation\u002F3.api\u002F3.bookings-auth",{"title":164,"path":165,"stem":166,"icon":167},"Bookings - Public & Guest","\u002Fbooki-documentation\u002Fapi\u002Fbookings-public","3.booki-documentation\u002F3.api\u002F3.bookings-public","i-lucide-calendar-plus",{"title":169,"path":170,"stem":171,"icon":172},"Booking Services","\u002Fbooki-documentation\u002Fapi\u002Fbooking-services","3.booki-documentation\u002F3.api\u002F4.booking-services","i-lucide-box",{"title":174,"path":175,"stem":176,"icon":177},"Organizations - Branches","\u002Fbooki-documentation\u002Fapi\u002Fbranches","3.booki-documentation\u002F3.api\u002F5.branches","i-lucide-git-branch",{"title":179,"path":180,"stem":181,"icon":182},"Organizations - Business Hours","\u002Fbooki-documentation\u002Fapi\u002Fbusiness-hours","3.booki-documentation\u002F3.api\u002F5.business-hours","i-lucide-clock",{"title":184,"path":185,"stem":186,"icon":187},"Organizations - Base","\u002Fbooki-documentation\u002Fapi\u002Forganizations","3.booki-documentation\u002F3.api\u002F5.organizations","i-lucide-building-2",{"title":189,"path":190,"stem":191,"icon":172},"Organizations - Packages","\u002Fbooki-documentation\u002Fapi\u002Fpackages","3.booki-documentation\u002F3.api\u002F5.packages",{"title":193,"path":194,"stem":195,"icon":196},"Organizations - Payments & Integrations","\u002Fbooki-documentation\u002Fapi\u002Fpayments","3.booki-documentation\u002F3.api\u002F5.payments","i-lucide-credit-card",{"title":198,"path":199,"stem":200,"icon":201},"Users - Profile & Settings","\u002Fbooki-documentation\u002Fapi\u002Fusers","3.booki-documentation\u002F3.api\u002F6.users","i-lucide-user",{"title":203,"path":204,"stem":205,"icon":196},"Maya Payments","\u002Fbooki-documentation\u002Fapi\u002Fmaya","3.booki-documentation\u002F3.api\u002F7.maya",{"title":207,"path":208,"stem":209,"icon":210},"Owner - Booking Management","\u002Fbooki-documentation\u002Fapi\u002Fowner-bookings","3.booki-documentation\u002F3.api\u002F7.owner-bookings","i-lucide-calendar",{"title":212,"path":213,"stem":214,"icon":215},"Owner - Customer Management","\u002Fbooki-documentation\u002Fapi\u002Fowner-customers","3.booki-documentation\u002F3.api\u002F7.owner-customers","i-lucide-users",{"title":217,"path":218,"stem":219,"icon":196},"Admin - Billing & Subscriptions","\u002Fbooki-documentation\u002Fapi\u002Fadmin-billing","3.booki-documentation\u002F3.api\u002F8.admin-billing",{"title":221,"path":222,"stem":223,"icon":187},"Admin - Organizations Management","\u002Fbooki-documentation\u002Fapi\u002Fadmin-organizations","3.booki-documentation\u002F3.api\u002F8.admin-organizations",{"title":225,"path":226,"stem":227,"icon":228},"Admin - User Management","\u002Fbooki-documentation\u002Fapi\u002Fadmin-users","3.booki-documentation\u002F3.api\u002F8.admin-users","i-lucide-shield-admin",{"title":230,"icon":231,"path":232,"stem":233,"children":234,"page":54},"Shared","i-lucide-package","\u002Fbooki-documentation\u002Fshared","3.booki-documentation\u002F4.shared",[235,240],{"title":236,"path":237,"stem":238,"icon":239},"codi-node-utils","\u002Fbooki-documentation\u002Fshared\u002Fcodi-node-utils","3.booki-documentation\u002F4.shared\u002F1.codi-node-utils","i-lucide-wrench",{"title":241,"path":242,"stem":243,"icon":124},"codi-layer","\u002Fbooki-documentation\u002Fshared\u002Fcodi-layer","3.booki-documentation\u002F4.shared\u002F2.codi-layer",{"title":245,"path":246,"stem":247,"children":248,"page":54},"Flowcharts","\u002Fbooki-documentation\u002Fflowcharts","3.booki-documentation\u002F5.flowcharts",[249,253],{"title":250,"path":251,"stem":252,"icon":158},"Owner Booking Management Flow","\u002Fbooki-documentation\u002Fflowcharts\u002Fowner-booking-management","3.booki-documentation\u002F5.flowcharts\u002F1.owner-booking-management",{"title":254,"path":255,"stem":256,"icon":167},"Customer Booking Flow","\u002Fbooki-documentation\u002Fflowcharts\u002Fcustomer-booking-flow","3.booki-documentation\u002F5.flowcharts\u002F2.customer-booking-flow",{"title":258,"path":259,"stem":260,"children":261,"page":54},"Guides","\u002Fbooki-documentation\u002Fguides","3.booki-documentation\u002Fguides",[262,267,271,275,280,285,290,294,298],{"title":263,"path":264,"stem":265,"icon":266},"Guide - Authentication Flow & Sessions","\u002Fbooki-documentation\u002Fguides\u002Fguides-auth-flow","3.booki-documentation\u002Fguides\u002Fguides-auth-flow","i-lucide-lock",{"title":268,"path":269,"stem":270,"icon":177},"Guide - Branch Management","\u002Fbooki-documentation\u002Fguides\u002Fguides-branch-management","3.booki-documentation\u002Fguides\u002Fguides-branch-management",{"title":272,"path":273,"stem":274,"icon":196},"Guide - Customer Payment Methods","\u002Fbooki-documentation\u002Fguides\u002Fguides-customer-payments","3.booki-documentation\u002Fguides\u002Fguides-customer-payments",{"title":276,"path":277,"stem":278,"icon":279},"Guide - Environment Setup","\u002Fbooki-documentation\u002Fguides\u002Fguides-environment-setup","3.booki-documentation\u002Fguides\u002Fguides-environment-setup","i-lucide-settings",{"title":281,"path":282,"stem":283,"icon":284},"Guide - Common Error Responses","\u002Fbooki-documentation\u002Fguides\u002Fguides-errors","3.booki-documentation\u002Fguides\u002Fguides-errors","i-lucide-alert-circle",{"title":286,"path":287,"stem":288,"icon":289},"Guide - Gmail SMTP Setup","\u002Fbooki-documentation\u002Fguides\u002Fguides-gmail-setup","3.booki-documentation\u002Fguides\u002Fguides-gmail-setup","i-lucide-mail",{"title":291,"path":292,"stem":293,"icon":124},"Guide - Multi-Tenancy & Tenant Slug Resolution","\u002Fbooki-documentation\u002Fguides\u002Fguides-multi-tenancy","3.booki-documentation\u002Fguides\u002Fguides-multi-tenancy",{"title":295,"path":296,"stem":297,"icon":48},"Guide - Redis Caching","\u002Fbooki-documentation\u002Fguides\u002Fguides-redis","3.booki-documentation\u002Fguides\u002Fguides-redis",{"title":299,"path":300,"stem":301,"icon":302},"Guide - Subscription Billing","\u002Fbooki-documentation\u002Fguides\u002Fguides-subscription-billing","3.booki-documentation\u002Fguides\u002Fguides-subscription-billing","i-lucide-receipt",{"id":304,"title":291,"body":305,"description":1878,"extension":1879,"links":1880,"meta":1881,"navigation":1882,"path":292,"seo":1883,"stem":293,"__hash__":1884},"docs\u002F3.booki-documentation\u002Fguides\u002Fguides-multi-tenancy.md",{"type":306,"value":307,"toc":1849},"minimark",[308,317,320,325,328,355,357,361,368,379,384,400,402,406,411,418,424,431,436,463,468,530,534,537,578,584,589,595,599,602,622,626,632,696,699,701,705,711,713,717,720,727,747,752,1018,1023,1034,1036,1040,1044,1047,1150,1153,1168,1172,1175,1221,1223,1237,1239,1243,1246,1306,1311,1328,1330,1334,1429,1433,1545,1547,1551,1555,1593,1597,1638,1640,1644,1650,1714,1719,1736,1738,1742,1747,1770,1775,1812,1818,1820,1824,1845],[309,310,311,312,316],"p",{},"The Booki platform uses ",[313,314,315],"strong",{},"subdomain-based multi-tenancy"," to serve multiple independent organizations from a single API instance. Each organization (tenant) has a unique slug that determines its data scope.",[318,319],"hr",{},[321,322,324],"h2",{"id":323},"what-is-multi-tenancy","What is Multi-Tenancy?",[309,326,327],{},"Multi-tenancy is an architecture where a single application serves multiple independent organizations, each believing they have a private instance but sharing underlying infrastructure. This provides:",[309,329,330,331,334,335,338,339,342,343,338,345,348,349,338,351,354],{},"✅ ",[313,332,333],{},"Cost efficiency"," — Reduced infrastructure overhead",[336,337],"br",{},"\n✅ ",[313,340,341],{},"Scalability"," — Single deployment scales to many customers",[336,344],{},[313,346,347],{},"Data isolation"," — Complete logical separation between tenants",[336,350],{},[313,352,353],{},"Simplified management"," — One API for all tenants",[318,356],{},[321,358,360],{"id":359},"subdomain-vs-slug","Subdomain vs. Slug",[309,362,363,364,367],{},"Every organization has a ",[313,365,366],{},"slug"," — a URL-friendly identifier used in multiple places:",[369,370,375],"pre",{"className":371,"code":373,"language":374},[372],"language-text","Slug: \"booki-salon\"\n\nSubdomain URL: https:\u002F\u002Fbooki-salon.booki.app\nAPI endpoint: https:\u002F\u002Fapi.booki.app\nTenant ID header: X-Tenant-Slug: booki-salon\n\nOrganization lookup: GET \u002Fapi\u002Ftenant\u002Fbooki-salon\n","text",[376,377,373],"code",{"__ignoreMap":378},"",[309,380,381],{},[313,382,383],{},"Slug rules:",[385,386,387,391,394,397],"ul",{},[388,389,390],"li",{},"Lowercase letters, numbers, hyphens only",[388,392,393],{},"3-50 characters long",[388,395,396],{},"Unique across platform",[388,398,399],{},"URL-safe",[318,401],{},[321,403,405],{"id":404},"how-tenant-resolution-works","How Tenant Resolution Works",[407,408,410],"h3",{"id":409},"method-1-subdomain-auto-detection-recommended","Method 1: Subdomain Auto-Detection (Recommended)",[309,412,413,414,417],{},"When a customer visits ",[376,415,416],{},"booki-salon.booki.app",", browsers send requests to:",[369,419,422],{"className":420,"code":421,"language":374},[372],"https:\u002F\u002Fbooki-salon.booki.app\u002Fprofile\n",[376,423,421],{"__ignoreMap":378},[309,425,426,427,430],{},"The API extracts the subdomain (",[376,428,429],{},"booki-salon",") from the request origin and automatically scopes all queries to that tenant.",[309,432,433],{},[313,434,435],{},"Process:",[437,438,439,442,448,453,460],"ol",{},[388,440,441],{},"Browser makes request from subdomain",[388,443,444,445],{},"API receives request headers including ",[376,446,447],{},"Host: booki-salon.booki.app",[388,449,450,451],{},"Middleware extracts subdomain: ",[376,452,429],{},[388,454,455,456,459],{},"Database queries filtered to ",[376,457,458],{},"organizationId"," matching that slug",[388,461,462],{},"Response contains only that tenant's data",[309,464,465],{},[313,466,467],{},"Request example:",[369,469,473],{"className":470,"code":471,"language":472,"meta":378,"style":378},"language-bash shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","curl -X GET https:\u002F\u002Fbooki-salon.booki.app\u002Fapi\u002Fbookings \\\n  --cookie \"access_token=eyJhbGc...\" \\\n  -H \"Origin: https:\u002F\u002Fbooki-salon.booki.app\"\n","bash",[376,474,475,498,516],{"__ignoreMap":378},[476,477,480,484,488,491,494],"span",{"class":478,"line":479},"line",1,[476,481,483],{"class":482},"sBMFI","curl",[476,485,487],{"class":486},"sfazB"," -X",[476,489,490],{"class":486}," GET",[476,492,493],{"class":486}," https:\u002F\u002Fbooki-salon.booki.app\u002Fapi\u002Fbookings",[476,495,497],{"class":496},"sTEyZ"," \\\n",[476,499,501,504,508,511,514],{"class":478,"line":500},2,[476,502,503],{"class":486},"  --cookie",[476,505,507],{"class":506},"sMK4o"," \"",[476,509,510],{"class":486},"access_token=eyJhbGc...",[476,512,513],{"class":506},"\"",[476,515,497],{"class":496},[476,517,519,522,524,527],{"class":478,"line":518},3,[476,520,521],{"class":486},"  -H",[476,523,507],{"class":506},[476,525,526],{"class":486},"Origin: https:\u002F\u002Fbooki-salon.booki.app",[476,528,529],{"class":506},"\"\n",[407,531,533],{"id":532},"method-2-header-based-apibackend-use","Method 2: Header-Based (API\u002FBackend Use)",[309,535,536],{},"For API clients (mobile apps, integration services), pass tenant slug in header:",[369,538,540],{"className":470,"code":539,"language":472,"meta":378,"style":378},"curl -X GET https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fbookings \\\n  --cookie \"access_token=eyJhbGc...\" \\\n  -H \"X-Tenant-Slug: booki-salon\"\n",[376,541,542,555,567],{"__ignoreMap":378},[476,543,544,546,548,550,553],{"class":478,"line":479},[476,545,483],{"class":482},[476,547,487],{"class":486},[476,549,490],{"class":486},[476,551,552],{"class":486}," https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fbookings",[476,554,497],{"class":496},[476,556,557,559,561,563,565],{"class":478,"line":500},[476,558,503],{"class":486},[476,560,507],{"class":506},[476,562,510],{"class":486},[476,564,513],{"class":506},[476,566,497],{"class":496},[476,568,569,571,573,576],{"class":478,"line":518},[476,570,521],{"class":486},[476,572,507],{"class":506},[476,574,575],{"class":486},"X-Tenant-Slug: booki-salon",[476,577,529],{"class":506},[309,579,580,581,583],{},"This tells the API: \"Scope this request to the ",[376,582,429],{}," organization.\"",[309,585,586],{},[313,587,588],{},"Header format:",[369,590,593],{"className":591,"code":592,"language":374},[372],"X-Tenant-Slug: booki-salon\n",[376,594,592],{"__ignoreMap":378},[407,596,598],{"id":597},"method-3-query-parameter-fallback","Method 3: Query Parameter (Fallback)",[309,600,601],{},"For public endpoints (like tenant lookup), use query parameter:",[369,603,605],{"className":470,"code":604,"language":472,"meta":378,"style":378},"curl -X GET \"https:\u002F\u002Fapi.booki.app\u002Fapi\u002Ftenant?slug=booki-salon\"\n",[376,606,607],{"__ignoreMap":378},[476,608,609,611,613,615,617,620],{"class":478,"line":479},[476,610,483],{"class":482},[476,612,487],{"class":486},[476,614,490],{"class":486},[476,616,507],{"class":506},[476,618,619],{"class":486},"https:\u002F\u002Fapi.booki.app\u002Fapi\u002Ftenant?slug=booki-salon",[476,621,529],{"class":506},[407,623,625],{"id":624},"method-4-route-parameter-direct-org-id","Method 4: Route Parameter (Direct Org ID)",[309,627,628,629,631],{},"Some endpoints accept ",[376,630,458],{}," directly in the URL path. No slug lookup is needed — the middleware uses the ID as-is:",[369,633,635],{"className":470,"code":634,"language":472,"meta":378,"style":378},"curl -X POST \"https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fv1\u002Fbookings\u002Forganizations\u002F507f191e810c19729de860ea\u002Ftype\u002Fhaircut\" \\\n  -H \"X-Branch-Slug: main-branch\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{...}'\n",[376,636,637,655,668,681],{"__ignoreMap":378},[476,638,639,641,643,646,648,651,653],{"class":478,"line":479},[476,640,483],{"class":482},[476,642,487],{"class":486},[476,644,645],{"class":486}," POST",[476,647,507],{"class":506},[476,649,650],{"class":486},"https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fv1\u002Fbookings\u002Forganizations\u002F507f191e810c19729de860ea\u002Ftype\u002Fhaircut",[476,652,513],{"class":506},[476,654,497],{"class":496},[476,656,657,659,661,664,666],{"class":478,"line":500},[476,658,521],{"class":486},[476,660,507],{"class":506},[476,662,663],{"class":486},"X-Branch-Slug: main-branch",[476,665,513],{"class":506},[476,667,497],{"class":496},[476,669,670,672,674,677,679],{"class":478,"line":518},[476,671,521],{"class":486},[476,673,507],{"class":506},[476,675,676],{"class":486},"Content-Type: application\u002Fjson",[476,678,513],{"class":506},[476,680,497],{"class":496},[476,682,684,687,690,693],{"class":478,"line":683},4,[476,685,686],{"class":486},"  -d",[476,688,689],{"class":506}," '",[476,691,692],{"class":486},"{...}",[476,694,695],{"class":506},"'\n",[309,697,698],{},"This is useful when a subdomain or tenant slug is unavailable (e.g., QR codes, direct links, or non-browser integrations).",[318,700],{},[321,702,704],{"id":703},"data-flow-diagram","Data Flow Diagram",[369,706,709],{"className":707,"code":708,"language":374},[372],"┌─────────────────────────────────────────────┐\n│         Client Request                      │\n│  GET \u002Fapi\u002Fbookings                          │\n│  Header: X-Tenant-Slug: booki-salon        │\n│  Cookie: access_token=...                  │\n└──────────────┬──────────────────────────────┘\n               │\n               ↓\n┌──────────────────────────────────────────────┐\n│    API Tenant Middleware                     │\n│  1. Extract tenant slug from:                │\n│     - Subdomain (if provided)               │\n│     - X-Tenant-Slug header                  │\n│     - Query param (if allowed)              │\n│  2. Resolve slug → organizationId           │\n│  3. Attach to request context               │\n└──────────────┬──────────────────────────────┘\n               │\n               ↓\n┌──────────────────────────────────────────────┐\n│    Authentication Middleware                │\n│  1. Validate JWT token                      │\n│  2. Verify user belongs to tenant           │\n│  3. Populate req.user with profile          │\n└──────────────┬──────────────────────────────┘\n               │\n               ↓\n┌──────────────────────────────────────────────┐\n│    Database Query (Scoped)                   │\n│  Booking.find({                             │\n│    organizationId: tenantContext.orgId,     │\n│    customerId: req.user._id                 │\n│  })                                         │\n└──────────────┬──────────────────────────────┘\n               │\n               ↓\n┌──────────────────────────────────────────────┐\n│    Response (Tenant-Isolated)               │\n│  Only bookings from booki-salon org         │\n│  No other tenants' data leaked              │\n└──────────────────────────────────────────────┘\n",[376,710,708],{"__ignoreMap":378},[318,712],{},[321,714,716],{"id":715},"tenant-slug-resolution-endpoint","Tenant Slug Resolution Endpoint",[309,718,719],{},"To resolve an organization from slug (public endpoint):",[407,721,723,724],{"id":722},"get-apitenantslug","GET ",[376,725,726],{},"\u002Fapi\u002Ftenant\u002F:slug",[369,728,730],{"className":470,"code":729,"language":472,"meta":378,"style":378},"curl -X GET \"https:\u002F\u002Fapi.booki.app\u002Fapi\u002Ftenant\u002Fbooki-salon\"\n",[376,731,732],{"__ignoreMap":378},[476,733,734,736,738,740,742,745],{"class":478,"line":479},[476,735,483],{"class":482},[476,737,487],{"class":486},[476,739,490],{"class":486},[476,741,507],{"class":506},[476,743,744],{"class":486},"https:\u002F\u002Fapi.booki.app\u002Fapi\u002Ftenant\u002Fbooki-salon",[476,746,529],{"class":506},[309,748,749],{},[313,750,751],{},"Response:",[369,753,757],{"className":754,"code":755,"language":756,"meta":378,"style":378},"language-json shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","{\n  \"_id\": \"507f191e810c19729de860ea\",\n  \"name\": \"Booki Salon\",\n  \"slug\": \"booki-salon\",\n  \"description\": \"Premium salon services\",\n  \"email\": \"owner@bookisalon.com\",\n  \"phone\": \"09161234567\",\n  \"website\": \"https:\u002F\u002Fbookisalon.com\",\n  \"address\": {\n    \"city\": \"Manila\",\n    \"country\": \"Philippines\"\n  },\n  \"plan\": \"PREMIUM\",\n  \"status\": \"ACTIVE\"\n}\n","json",[376,758,759,764,788,808,826,847,868,889,910,925,947,966,972,993,1012],{"__ignoreMap":378},[476,760,761],{"class":478,"line":479},[476,762,763],{"class":506},"{\n",[476,765,766,769,773,775,778,780,783,785],{"class":478,"line":500},[476,767,768],{"class":506},"  \"",[476,770,772],{"class":771},"spNyl","_id",[476,774,513],{"class":506},[476,776,777],{"class":506},":",[476,779,507],{"class":506},[476,781,782],{"class":486},"507f191e810c19729de860ea",[476,784,513],{"class":506},[476,786,787],{"class":506},",\n",[476,789,790,792,795,797,799,801,804,806],{"class":478,"line":518},[476,791,768],{"class":506},[476,793,794],{"class":771},"name",[476,796,513],{"class":506},[476,798,777],{"class":506},[476,800,507],{"class":506},[476,802,803],{"class":486},"Booki Salon",[476,805,513],{"class":506},[476,807,787],{"class":506},[476,809,810,812,814,816,818,820,822,824],{"class":478,"line":683},[476,811,768],{"class":506},[476,813,366],{"class":771},[476,815,513],{"class":506},[476,817,777],{"class":506},[476,819,507],{"class":506},[476,821,429],{"class":486},[476,823,513],{"class":506},[476,825,787],{"class":506},[476,827,829,831,834,836,838,840,843,845],{"class":478,"line":828},5,[476,830,768],{"class":506},[476,832,833],{"class":771},"description",[476,835,513],{"class":506},[476,837,777],{"class":506},[476,839,507],{"class":506},[476,841,842],{"class":486},"Premium salon services",[476,844,513],{"class":506},[476,846,787],{"class":506},[476,848,850,852,855,857,859,861,864,866],{"class":478,"line":849},6,[476,851,768],{"class":506},[476,853,854],{"class":771},"email",[476,856,513],{"class":506},[476,858,777],{"class":506},[476,860,507],{"class":506},[476,862,863],{"class":486},"owner@bookisalon.com",[476,865,513],{"class":506},[476,867,787],{"class":506},[476,869,871,873,876,878,880,882,885,887],{"class":478,"line":870},7,[476,872,768],{"class":506},[476,874,875],{"class":771},"phone",[476,877,513],{"class":506},[476,879,777],{"class":506},[476,881,507],{"class":506},[476,883,884],{"class":486},"09161234567",[476,886,513],{"class":506},[476,888,787],{"class":506},[476,890,892,894,897,899,901,903,906,908],{"class":478,"line":891},8,[476,893,768],{"class":506},[476,895,896],{"class":771},"website",[476,898,513],{"class":506},[476,900,777],{"class":506},[476,902,507],{"class":506},[476,904,905],{"class":486},"https:\u002F\u002Fbookisalon.com",[476,907,513],{"class":506},[476,909,787],{"class":506},[476,911,913,915,918,920,922],{"class":478,"line":912},9,[476,914,768],{"class":506},[476,916,917],{"class":771},"address",[476,919,513],{"class":506},[476,921,777],{"class":506},[476,923,924],{"class":506}," {\n",[476,926,928,931,934,936,938,940,943,945],{"class":478,"line":927},10,[476,929,930],{"class":506},"    \"",[476,932,933],{"class":482},"city",[476,935,513],{"class":506},[476,937,777],{"class":506},[476,939,507],{"class":506},[476,941,942],{"class":486},"Manila",[476,944,513],{"class":506},[476,946,787],{"class":506},[476,948,950,952,955,957,959,961,964],{"class":478,"line":949},11,[476,951,930],{"class":506},[476,953,954],{"class":482},"country",[476,956,513],{"class":506},[476,958,777],{"class":506},[476,960,507],{"class":506},[476,962,963],{"class":486},"Philippines",[476,965,529],{"class":506},[476,967,969],{"class":478,"line":968},12,[476,970,971],{"class":506},"  },\n",[476,973,975,977,980,982,984,986,989,991],{"class":478,"line":974},13,[476,976,768],{"class":506},[476,978,979],{"class":771},"plan",[476,981,513],{"class":506},[476,983,777],{"class":506},[476,985,507],{"class":506},[476,987,988],{"class":486},"PREMIUM",[476,990,513],{"class":506},[476,992,787],{"class":506},[476,994,996,998,1001,1003,1005,1007,1010],{"class":478,"line":995},14,[476,997,768],{"class":506},[476,999,1000],{"class":771},"status",[476,1002,513],{"class":506},[476,1004,777],{"class":506},[476,1006,507],{"class":506},[476,1008,1009],{"class":486},"ACTIVE",[476,1011,529],{"class":506},[476,1013,1015],{"class":478,"line":1014},15,[476,1016,1017],{"class":506},"}\n",[309,1019,1020],{},[313,1021,1022],{},"Use cases:",[385,1024,1025,1028,1031],{},[388,1026,1027],{},"Guest booking form needs to load org details",[388,1029,1030],{},"Mobile app needs public organization info",[388,1032,1033],{},"Tenant lookup for slug resolution",[318,1035],{},[321,1037,1039],{"id":1038},"multi-tenancy-in-practice","Multi-Tenancy in Practice",[407,1041,1043],{"id":1042},"public-endpoints-no-auth","Public Endpoints (No Auth)",[309,1045,1046],{},"Guest users booking without login still need tenant context:",[369,1048,1050],{"className":470,"code":1049,"language":472,"meta":378,"style":378},"# Guest creates booking for booki-salon\ncurl -X POST https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fbookings\u002Ftype\u002Fhaircut \\\n  -H \"X-Tenant-Slug: booki-salon\" \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"organizationId\": \"507f191e810c19729de860ea\",\n    \"packageId\": \"507f1f77bcf86cd799439031\",\n    \"bookingDate\": \"2026-04-10\",\n    \"bookingTime\": \"14:30\",\n    \"firstName\": \"John\",\n    \"lastName\": \"Smith\",\n    \"email\": \"john@example.com\",\n    \"phone\": \"09161234567\"\n  }'\n",[376,1051,1052,1058,1071,1083,1095,1103,1108,1113,1118,1123,1128,1133,1138,1143],{"__ignoreMap":378},[476,1053,1054],{"class":478,"line":479},[476,1055,1057],{"class":1056},"sHwdD","# Guest creates booking for booki-salon\n",[476,1059,1060,1062,1064,1066,1069],{"class":478,"line":500},[476,1061,483],{"class":482},[476,1063,487],{"class":486},[476,1065,645],{"class":486},[476,1067,1068],{"class":486}," https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fbookings\u002Ftype\u002Fhaircut",[476,1070,497],{"class":496},[476,1072,1073,1075,1077,1079,1081],{"class":478,"line":518},[476,1074,521],{"class":486},[476,1076,507],{"class":506},[476,1078,575],{"class":486},[476,1080,513],{"class":506},[476,1082,497],{"class":496},[476,1084,1085,1087,1089,1091,1093],{"class":478,"line":683},[476,1086,521],{"class":486},[476,1088,507],{"class":506},[476,1090,676],{"class":486},[476,1092,513],{"class":506},[476,1094,497],{"class":496},[476,1096,1097,1099,1101],{"class":478,"line":828},[476,1098,686],{"class":486},[476,1100,689],{"class":506},[476,1102,763],{"class":486},[476,1104,1105],{"class":478,"line":849},[476,1106,1107],{"class":486},"    \"organizationId\": \"507f191e810c19729de860ea\",\n",[476,1109,1110],{"class":478,"line":870},[476,1111,1112],{"class":486},"    \"packageId\": \"507f1f77bcf86cd799439031\",\n",[476,1114,1115],{"class":478,"line":891},[476,1116,1117],{"class":486},"    \"bookingDate\": \"2026-04-10\",\n",[476,1119,1120],{"class":478,"line":912},[476,1121,1122],{"class":486},"    \"bookingTime\": \"14:30\",\n",[476,1124,1125],{"class":478,"line":927},[476,1126,1127],{"class":486},"    \"firstName\": \"John\",\n",[476,1129,1130],{"class":478,"line":949},[476,1131,1132],{"class":486},"    \"lastName\": \"Smith\",\n",[476,1134,1135],{"class":478,"line":968},[476,1136,1137],{"class":486},"    \"email\": \"john@example.com\",\n",[476,1139,1140],{"class":478,"line":974},[476,1141,1142],{"class":486},"    \"phone\": \"09161234567\"\n",[476,1144,1145,1148],{"class":478,"line":995},[476,1146,1147],{"class":486},"  }",[476,1149,695],{"class":506},[309,1151,1152],{},"The API:",[437,1154,1155,1160,1163],{},[388,1156,1157,1158],{},"Extracts tenant slug: ",[376,1159,429],{},[388,1161,1162],{},"Verifies booking request is for that organization",[388,1164,1165,1166],{},"Creates booking scoped to ",[376,1167,429],{},[407,1169,1171],{"id":1170},"authenticated-endpoints","Authenticated Endpoints",[309,1173,1174],{},"Logged-in users automatically get their tenant context from token:",[369,1176,1178],{"className":470,"code":1177,"language":472,"meta":378,"style":378},"# Owner viewing their bookings (tenant auto-detected from JWT)\ncurl -X GET https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fadmin\u002Fbookings\u002Fcalendar?date=2026-04-01 \\\n  --cookie \"access_token=OWNER_JWT_TOKEN\" \\\n  -H \"X-Tenant-Slug: booki-salon\"\n",[376,1179,1180,1185,1198,1211],{"__ignoreMap":378},[476,1181,1182],{"class":478,"line":479},[476,1183,1184],{"class":1056},"# Owner viewing their bookings (tenant auto-detected from JWT)\n",[476,1186,1187,1189,1191,1193,1196],{"class":478,"line":500},[476,1188,483],{"class":482},[476,1190,487],{"class":486},[476,1192,490],{"class":486},[476,1194,1195],{"class":486}," https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fadmin\u002Fbookings\u002Fcalendar?date=2026-04-01",[476,1197,497],{"class":496},[476,1199,1200,1202,1204,1207,1209],{"class":478,"line":518},[476,1201,503],{"class":486},[476,1203,507],{"class":506},[476,1205,1206],{"class":486},"access_token=OWNER_JWT_TOKEN",[476,1208,513],{"class":506},[476,1210,497],{"class":496},[476,1212,1213,1215,1217,1219],{"class":478,"line":683},[476,1214,521],{"class":486},[476,1216,507],{"class":506},[476,1218,575],{"class":486},[476,1220,529],{"class":506},[309,1222,1152],{},[437,1224,1225,1228,1231,1234],{},[388,1226,1227],{},"Validates JWT token",[388,1229,1230],{},"Reads user's organization from token",[388,1232,1233],{},"Verifies JWT org matches header slug (security check)",[388,1235,1236],{},"Returns only that organization's bookings",[318,1238],{},[321,1240,1242],{"id":1241},"data-isolation-guarantees","Data Isolation Guarantees",[309,1244,1245],{},"Every database query includes tenant filter:",[369,1247,1251],{"className":1248,"code":1249,"language":1250,"meta":378,"style":378},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","\u002F\u002F CORRECT: Tenant-scoped query\nconst bookings = await Booking.find({\n  organizationId: tenantContext.orgId, \u002F\u002F Auto-populated\n  customerId: userId,\n});\n\n\u002F\u002F WRONG: Missing tenant filter (would leak data)\nconst bookings = await Booking.find({\n  customerId: userId,\n  \u002F\u002F ❌ No organizationId check = could see other tenants' data\n});\n","javascript",[376,1252,1253,1258,1263,1268,1273,1278,1284,1289,1293,1297,1302],{"__ignoreMap":378},[476,1254,1255],{"class":478,"line":479},[476,1256,1257],{},"\u002F\u002F CORRECT: Tenant-scoped query\n",[476,1259,1260],{"class":478,"line":500},[476,1261,1262],{},"const bookings = await Booking.find({\n",[476,1264,1265],{"class":478,"line":518},[476,1266,1267],{},"  organizationId: tenantContext.orgId, \u002F\u002F Auto-populated\n",[476,1269,1270],{"class":478,"line":683},[476,1271,1272],{},"  customerId: userId,\n",[476,1274,1275],{"class":478,"line":828},[476,1276,1277],{},"});\n",[476,1279,1280],{"class":478,"line":849},[476,1281,1283],{"emptyLinePlaceholder":1282},true,"\n",[476,1285,1286],{"class":478,"line":870},[476,1287,1288],{},"\u002F\u002F WRONG: Missing tenant filter (would leak data)\n",[476,1290,1291],{"class":478,"line":891},[476,1292,1262],{},[476,1294,1295],{"class":478,"line":912},[476,1296,1272],{},[476,1298,1299],{"class":478,"line":927},[476,1300,1301],{},"  \u002F\u002F ❌ No organizationId check = could see other tenants' data\n",[476,1303,1304],{"class":478,"line":949},[476,1305,1277],{},[309,1307,1308],{},[313,1309,1310],{},"Security enforcement:",[385,1312,1313,1316,1322,1325],{},[388,1314,1315],{},"Middleware validates tenant on every request",[388,1317,1318,1319,1321],{},"All models include ",[376,1320,458],{}," unique index",[388,1323,1324],{},"No query bypasses tenant check",[388,1326,1327],{},"Deleted organizations cannot be accessed",[318,1329],{},[321,1331,1333],{"id":1332},"common-tenant-issues-troubleshooting","Common Tenant Issues & Troubleshooting",[1335,1336,1337,1353],"table",{},[1338,1339,1340],"thead",{},[1341,1342,1343,1347,1350],"tr",{},[1344,1345,1346],"th",{},"Error",[1344,1348,1349],{},"Cause",[1344,1351,1352],{},"Solution",[1354,1355,1356,1373,1386,1403,1416],"tbody",{},[1341,1357,1358,1364,1367],{},[1359,1360,1361],"td",{},[376,1362,1363],{},"Tenant not found",[1359,1365,1366],{},"Invalid or missing slug",[1359,1368,1369,1370,1372],{},"Verify slug exists; check spelling; use GET ",[376,1371,726],{}," first",[1341,1374,1375,1380,1383],{},[1359,1376,1377],{},[376,1378,1379],{},"Unauthorized - tenant mismatch",[1359,1381,1382],{},"JWT token from different org",[1359,1384,1385],{},"Ensure logged-in user matches requested tenant",[1341,1387,1388,1393,1396],{},[1359,1389,1390],{},[376,1391,1392],{},"No X-Tenant-Slug header",[1359,1394,1395],{},"Missing required header for API call",[1359,1397,1398,1399,1402],{},"Add ",[376,1400,1401],{},"-H \"X-Tenant-Slug: booki-salon\""," to request",[1341,1404,1405,1410,1413],{},[1359,1406,1407],{},[376,1408,1409],{},"organizationId not found",[1359,1411,1412],{},"Submitted ID doesn't match tenant",[1359,1414,1415],{},"Verify organization ID belongs to intended tenant",[1341,1417,1418,1423,1426],{},[1359,1419,1420],{},[376,1421,1422],{},"403 Permission Denied",[1359,1424,1425],{},"User not member of tenant",[1359,1427,1428],{},"Check user's organizationId in profile",[407,1430,1432],{"id":1431},"debug-checklist","Debug Checklist",[437,1434,1435,1459,1509,1532],{},[388,1436,1437,1440,1456,1458],{},[313,1438,1439],{},"Do I have the correct slug?",[369,1441,1443],{"className":470,"code":1442,"language":472,"meta":378,"style":378},"curl -X GET https:\u002F\u002Fapi.booki.app\u002Fapi\u002Ftenant\u002FYOUR-SLUG\n",[376,1444,1445],{"__ignoreMap":378},[476,1446,1447,1449,1451,1453],{"class":478,"line":479},[476,1448,483],{"class":482},[476,1450,487],{"class":486},[476,1452,490],{"class":486},[476,1454,1455],{"class":486}," https:\u002F\u002Fapi.booki.app\u002Fapi\u002Ftenant\u002FYOUR-SLUG\n",[336,1457],{},"Should return 200 with org details.",[388,1460,1461,1464,1506,1508],{},[313,1462,1463],{},"Is my token valid?",[369,1465,1467],{"className":470,"code":1466,"language":472,"meta":378,"style":378},"curl -X GET https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fauth\u002Fuser \\\n  --cookie \"access_token=YOUR_TOKEN\" \\\n  -H \"X-Tenant-Slug: YOUR-SLUG\"\n",[376,1468,1469,1482,1495],{"__ignoreMap":378},[476,1470,1471,1473,1475,1477,1480],{"class":478,"line":479},[476,1472,483],{"class":482},[476,1474,487],{"class":486},[476,1476,490],{"class":486},[476,1478,1479],{"class":486}," https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fauth\u002Fuser",[476,1481,497],{"class":496},[476,1483,1484,1486,1488,1491,1493],{"class":478,"line":500},[476,1485,503],{"class":486},[476,1487,507],{"class":506},[476,1489,1490],{"class":486},"access_token=YOUR_TOKEN",[476,1492,513],{"class":506},[476,1494,497],{"class":496},[476,1496,1497,1499,1501,1504],{"class":478,"line":518},[476,1498,521],{"class":486},[476,1500,507],{"class":506},[476,1502,1503],{"class":486},"X-Tenant-Slug: YOUR-SLUG",[476,1505,529],{"class":506},[336,1507],{},"Should return your user profile.",[388,1510,1511,1514],{},[313,1512,1513],{},"Are tenant and token aligned?",[385,1515,1516,1522,1529],{},[388,1517,1518,1519,1521],{},"Extract ",[376,1520,458],{}," from JWT (payload)",[388,1523,1524,1525,1528],{},"Compare with slug via ",[376,1526,1527],{},"GET \u002Fapi\u002Ftenant\u002F:slug"," response",[388,1530,1531],{},"Both must match",[388,1533,1534,1537],{},[313,1535,1536],{},"Is the resource scoped correctly?",[385,1538,1539,1542],{},[388,1540,1541],{},"Try fetching with wrong tenant header",[388,1543,1544],{},"Should get 404 or 403, not 200",[318,1546],{},[321,1548,1550],{"id":1549},"tenant-contexts-frontend-vs-backend","Tenant Contexts: Frontend vs Backend",[407,1552,1554],{"id":1553},"frontend-web-app","Frontend (Web App)",[369,1556,1558],{"className":1248,"code":1557,"language":1250,"meta":378,"style":378},"\u002F\u002F www.booki-salon.booki.app\n\u002F\u002F Subdomain auto-detected by browser\n\nfetch(\"https:\u002F\u002Fbooki-salon.booki.app\u002Fapi\u002Fbookings\", {\n  credentials: \"include\", \u002F\u002F Include HttpOnly cookies\n});\n\u002F\u002F Tenant: auto from subdomain \"booki-salon\"\n",[376,1559,1560,1565,1570,1574,1579,1584,1588],{"__ignoreMap":378},[476,1561,1562],{"class":478,"line":479},[476,1563,1564],{},"\u002F\u002F www.booki-salon.booki.app\n",[476,1566,1567],{"class":478,"line":500},[476,1568,1569],{},"\u002F\u002F Subdomain auto-detected by browser\n",[476,1571,1572],{"class":478,"line":518},[476,1573,1283],{"emptyLinePlaceholder":1282},[476,1575,1576],{"class":478,"line":683},[476,1577,1578],{},"fetch(\"https:\u002F\u002Fbooki-salon.booki.app\u002Fapi\u002Fbookings\", {\n",[476,1580,1581],{"class":478,"line":828},[476,1582,1583],{},"  credentials: \"include\", \u002F\u002F Include HttpOnly cookies\n",[476,1585,1586],{"class":478,"line":849},[476,1587,1277],{},[476,1589,1590],{"class":478,"line":870},[476,1591,1592],{},"\u002F\u002F Tenant: auto from subdomain \"booki-salon\"\n",[407,1594,1596],{"id":1595},"backend-api-service-mobile-app","Backend (API Service, Mobile App)",[369,1598,1600],{"className":1248,"code":1599,"language":1250,"meta":378,"style":378},"\u002F\u002F Must explicitly pass tenant\nconst response = await fetch(\"https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fbookings\", {\n  headers: {\n    \"X-Tenant-Slug\": \"booki-salon\", \u002F\u002F ← Required\n    Authorization: `Bearer ${token}`,\n  },\n});\n",[376,1601,1602,1607,1612,1617,1625,1630,1634],{"__ignoreMap":378},[476,1603,1604],{"class":478,"line":479},[476,1605,1606],{},"\u002F\u002F Must explicitly pass tenant\n",[476,1608,1609],{"class":478,"line":500},[476,1610,1611],{},"const response = await fetch(\"https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fbookings\", {\n",[476,1613,1614],{"class":478,"line":518},[476,1615,1616],{},"  headers: {\n",[476,1618,1619,1622],{"class":478,"line":683},[476,1620,1621],{},"    \"X-Tenant-Slug\": \"booki-salon\",",[476,1623,1624],{}," \u002F\u002F ← Required\n",[476,1626,1627],{"class":478,"line":828},[476,1628,1629],{},"    Authorization: `Bearer ${token}`,\n",[476,1631,1632],{"class":478,"line":849},[476,1633,971],{},[476,1635,1636],{"class":478,"line":870},[476,1637,1277],{},[318,1639],{},[321,1641,1643],{"id":1642},"advanced-cross-tenant-operations","Advanced: Cross-Tenant Operations",[309,1645,1646,1649],{},[313,1647,1648],{},"Important:"," The Booki API does NOT support cross-tenant queries.",[369,1651,1653],{"className":470,"code":1652,"language":472,"meta":378,"style":378},"# ❌ INVALID: Cannot query bookings from multiple tenants in one request\ncurl -X POST https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fbookings\u002Fmulti-search \\\n  -H \"Content-Type: application\u002Fjson\" \\\n  -d '{\n    \"tenants\": [\"booki-salon\", \"fitness-center\"],\n    \"date\": \"2026-04-10\"\n  }'\n# Would return 403: Cross-tenant access denied\n",[376,1654,1655,1660,1673,1685,1693,1698,1703,1709],{"__ignoreMap":378},[476,1656,1657],{"class":478,"line":479},[476,1658,1659],{"class":1056},"# ❌ INVALID: Cannot query bookings from multiple tenants in one request\n",[476,1661,1662,1664,1666,1668,1671],{"class":478,"line":500},[476,1663,483],{"class":482},[476,1665,487],{"class":486},[476,1667,645],{"class":486},[476,1669,1670],{"class":486}," https:\u002F\u002Fapi.booki.app\u002Fapi\u002Fbookings\u002Fmulti-search",[476,1672,497],{"class":496},[476,1674,1675,1677,1679,1681,1683],{"class":478,"line":518},[476,1676,521],{"class":486},[476,1678,507],{"class":506},[476,1680,676],{"class":486},[476,1682,513],{"class":506},[476,1684,497],{"class":496},[476,1686,1687,1689,1691],{"class":478,"line":683},[476,1688,686],{"class":486},[476,1690,689],{"class":506},[476,1692,763],{"class":486},[476,1694,1695],{"class":478,"line":828},[476,1696,1697],{"class":486},"    \"tenants\": [\"booki-salon\", \"fitness-center\"],\n",[476,1699,1700],{"class":478,"line":849},[476,1701,1702],{"class":486},"    \"date\": \"2026-04-10\"\n",[476,1704,1705,1707],{"class":478,"line":870},[476,1706,1147],{"class":486},[476,1708,695],{"class":506},[476,1710,1711],{"class":478,"line":891},[476,1712,1713],{"class":1056},"# Would return 403: Cross-tenant access denied\n",[309,1715,1716],{},[313,1717,1718],{},"If you need data from multiple tenants:",[437,1720,1721,1724,1727],{},[388,1722,1723],{},"Make separate API calls for each tenant",[388,1725,1726],{},"Merge results in your application",[388,1728,1729],{},[313,1730,1731,1732,1735],{},"Each call must have correct ",[376,1733,1734],{},"X-Tenant-Slug"," header",[318,1737],{},[321,1739,1741],{"id":1740},"summary","Summary",[309,1743,1744],{},[313,1745,1746],{},"Key Points:",[385,1748,1749,1752,1758,1761,1764],{},[388,1750,1751],{},"✅ Every request is automatically scoped to a tenant",[388,1753,1754,1755,1757],{},"✅ Tenant determined by subdomain (web) or ",[376,1756,1734],{}," header (API)",[388,1759,1760],{},"✅ Data strictly isolated — no cross-tenant leaks",[388,1762,1763],{},"✅ User permissions verified — token org must match request tenant",[388,1765,1766,1767,1769],{},"✅ All database queries include ",[376,1768,458],{}," filter",[309,1771,1772],{},[313,1773,1774],{},"Tenant Resolution Priority (Desktop Web → Mobile API):",[437,1776,1777,1786,1794,1803],{},[388,1778,1779,1782,1783,1785],{},[313,1780,1781],{},"Subdomain"," (highest): ",[376,1784,416],{}," → auto-detected",[388,1787,1788,1791,1792],{},[313,1789,1790],{},"Header",": ",[376,1793,575],{},[388,1795,1796,1799,1800,1802],{},[313,1797,1798],{},"JWT Token",": Extract ",[376,1801,458],{}," from JWT payload",[388,1804,1805,1808,1809],{},[313,1806,1807],{},"Query Param"," (lowest, public only): ",[376,1810,1811],{},"?slug=booki-salon",[309,1813,1814,1817],{},[313,1815,1816],{},"Remember:"," Tenant context is NOT optional. Every request must have one.",[318,1819],{},[321,1821,1823],{"id":1822},"related","Related",[385,1825,1826,1833,1839],{},[388,1827,1828],{},[1829,1830,1832],"a",{"href":1831},"..\u002Fapi\u002Fbooki-api#key-concepts","Booki API Reference — Key Concepts",[388,1834,1835],{},[1829,1836,1838],{"href":1837},"..\u002Fapi\u002Forganizations","Organizations - Tenant Lookup",[388,1840,1841],{},[1829,1842,1844],{"href":1843},"..\u002F3.local-development","Local Development URLs",[1846,1847,1848],"style",{},"html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}",{"title":378,"searchDepth":479,"depth":500,"links":1850},[1851,1852,1853,1859,1860,1863,1867,1868,1871,1875,1876,1877],{"id":323,"depth":500,"text":324},{"id":359,"depth":500,"text":360},{"id":404,"depth":500,"text":405,"children":1854},[1855,1856,1857,1858],{"id":409,"depth":518,"text":410},{"id":532,"depth":518,"text":533},{"id":597,"depth":518,"text":598},{"id":624,"depth":518,"text":625},{"id":703,"depth":500,"text":704},{"id":715,"depth":500,"text":716,"children":1861},[1862],{"id":722,"depth":518,"text":1527},{"id":1038,"depth":500,"text":1039,"children":1864},[1865,1866],{"id":1042,"depth":518,"text":1043},{"id":1170,"depth":518,"text":1171},{"id":1241,"depth":500,"text":1242},{"id":1332,"depth":500,"text":1333,"children":1869},[1870],{"id":1431,"depth":518,"text":1432},{"id":1549,"depth":500,"text":1550,"children":1872},[1873,1874],{"id":1553,"depth":518,"text":1554},{"id":1595,"depth":518,"text":1596},{"id":1642,"depth":500,"text":1643},{"id":1740,"depth":500,"text":1741},{"id":1822,"depth":500,"text":1823},"Understanding multi-tenant architecture, data isolation, and tenant slug resolution strategies.","md",null,{},{"icon":124},{"title":291,"description":1878},"7z3vZwjkXMxdoCG1nGNbad3dCRm8RERJXHMiyX-yuEE",[1886,1888],{"title":286,"path":287,"stem":288,"description":1887,"icon":289,"children":-1},"How to generate a Gmail App Password and configure GMAIL_USER and GMAIL_APP_PASSWORD for the booki-api email service.",{"title":295,"path":296,"stem":297,"description":1889,"icon":48,"children":-1},"Redis setup, cache key patterns, and common CLI commands used in booki-api.",1777787842938]