{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":["tabs","tab"]},"type":"markdown"},"seo":{"title":"Hubby WebView","description":"Integrate Hubby eSIM into your travel platform with our comprehensive API documentation, tutorials, and guides.","keywords":"hubby, esim, api, travel, integration, documentation"},"dynamicMarkdocComponents":[],"compilationErrors":[],"ast":{"$$mdtype":"Tag","name":"article","attributes":{},"children":[{"$$mdtype":"Tag","name":"Heading","attributes":{"level":1,"id":"hubby-webview"},"children":["Hubby WebView"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Hubby provides a fully managed web app that runs inside your mobile app's in-app browser. Your travelers claim packages, install their eSIM, monitor data usage, and buy top-ups — all within a branded experience you control. Your backend makes two API calls. Hubby handles everything else."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This page covers the complete flow: what you build, what Hubby handles, every API call in sequence, how authentication works, and what to do after you go live."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-you-build-vs.-what-hubby-handles"},"children":["What You Build vs. What Hubby Handles"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Your team"},"children":["Your team"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Hubby"},"children":["Hubby"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Backend calls to create bookings and redirect tokens"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Package provisioning, eSIM assignment, region optimization"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["WebView container in your app (open a URL)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Branded UI: claiming flow, installation instructions, data meter, top-up store"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Pass device info as query parameters when opening the WebView"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Device-tailored installation guides, localized UI"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Store ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," per traveler"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Session management, token exchange, JWT lifecycle"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Map webhook events to push notifications (Phase 2)"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Webhook event delivery, departure-time CRM triggers"]}]}]}]}]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Effort estimate:"]}," Backend: 3–5 days. Mobile: 2–3 days. No frontend build required — your app opens a URL."]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"architecture"},"children":["Architecture"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Three actors are involved: your backend, the Hubby API, and the Hubby WebView running inside your app."]},{"$$mdtype":"Tag","name":"Mermaid","attributes":{"data-language":"mermaid","diagramSource":"sequenceDiagram\n    participant PB as Partner Backend\n    participant API as Hubby API\n    participant WV as Hubby WebView<br/>(in Partner App)\n\n    PB->>API: POST /api/bookings\n    API-->>PB: booking confirmation + package IDs\n\n    PB->>API: POST /api/redirect-tokens/create\n    API-->>PB: redirect_token (valid 5 min)\n\n    PB->>WV: Open WebView with redirect_token\n\n    WV->>API: POST /api/webapp/auth/exchange\n    API-->>WV: session JWT\n\n    WV->>API: GET /api/webapp/me/dashboard\n    API-->>WV: user dashboard data\n\n    WV->>WV: User claims packages,<br/>installs eSIM, monitors data\n","diagramHtml":"<div class=\"mermaid\" data-processed=\"true\"><svg id=\"mermaid-1777275990952\" width=\"100%\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" style=\"max-width: 941px;\" viewBox=\"-50 -10 941 763\" role=\"graphics-document document\" aria-roledescription=\"sequence\"><g><rect x=\"662\" y=\"677\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"WV\" rx=\"3\" ry=\"3\" class=\"actor actor-bottom\"></rect><text x=\"737\" y=\"709.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"737\" dy=\"-8\">Hubby WebView</tspan></text><text x=\"737\" y=\"709.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"737\" dy=\"8\">(in Partner App)</tspan></text></g><g><rect x=\"337\" y=\"677\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"API\" rx=\"3\" ry=\"3\" class=\"actor actor-bottom\"></rect><text x=\"412\" y=\"709.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"412\" dy=\"0\">Hubby API</tspan></text></g><g><rect x=\"0\" y=\"677\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"PB\" rx=\"3\" ry=\"3\" class=\"actor actor-bottom\"></rect><text x=\"75\" y=\"709.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"75\" dy=\"0\">Partner Backend</tspan></text></g><g><line id=\"actor2\" x1=\"737\" y1=\"65\" x2=\"737\" y2=\"677\" class=\"actor-line 200\" stroke-width=\"0.5px\" stroke=\"#999\" name=\"WV\"></line><g id=\"root-2\"><rect x=\"662\" y=\"0\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"WV\" rx=\"3\" ry=\"3\" class=\"actor actor-top\"></rect><text x=\"737\" y=\"32.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"737\" dy=\"-8\">Hubby WebView</tspan></text><text x=\"737\" y=\"32.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"737\" dy=\"8\">(in Partner App)</tspan></text></g></g><g><line id=\"actor1\" x1=\"412\" y1=\"65\" x2=\"412\" y2=\"677\" class=\"actor-line 200\" stroke-width=\"0.5px\" stroke=\"#999\" name=\"API\"></line><g id=\"root-1\"><rect x=\"337\" y=\"0\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"API\" rx=\"3\" ry=\"3\" class=\"actor actor-top\"></rect><text x=\"412\" y=\"32.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"412\" dy=\"0\">Hubby API</tspan></text></g></g><g><line id=\"actor0\" x1=\"75\" y1=\"65\" x2=\"75\" y2=\"677\" class=\"actor-line 200\" stroke-width=\"0.5px\" stroke=\"#999\" name=\"PB\"></line><g id=\"root-0\"><rect x=\"0\" y=\"0\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"PB\" rx=\"3\" ry=\"3\" class=\"actor actor-top\"></rect><text x=\"75\" y=\"32.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"75\" dy=\"0\">Partner Backend</tspan></text></g></g><style>#mermaid-1777275990952{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-1777275990952 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-1777275990952 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-1777275990952 .error-icon{fill:#552222;}#mermaid-1777275990952 .error-text{fill:#552222;stroke:#552222;}#mermaid-1777275990952 .edge-thickness-normal{stroke-width:1px;}#mermaid-1777275990952 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1777275990952 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1777275990952 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-1777275990952 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1777275990952 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1777275990952 .marker{fill:#333333;stroke:#333333;}#mermaid-1777275990952 .marker.cross{stroke:#333333;}#mermaid-1777275990952 svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-1777275990952 p{margin:0;}#mermaid-1777275990952 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-1777275990952 text.actor&gt;tspan{fill:black;stroke:none;}#mermaid-1777275990952 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-1777275990952 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-1777275990952 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-1777275990952 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-1777275990952 #arrowhead path{fill:#333;stroke:#333;}#mermaid-1777275990952 .sequenceNumber{fill:white;}#mermaid-1777275990952 #sequencenumber{fill:#333;}#mermaid-1777275990952 #crosshead path{fill:#333;stroke:#333;}#mermaid-1777275990952 .messageText{fill:#333;stroke:none;}#mermaid-1777275990952 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-1777275990952 .labelText,#mermaid-1777275990952 .labelText&gt;tspan{fill:black;stroke:none;}#mermaid-1777275990952 .loopText,#mermaid-1777275990952 .loopText&gt;tspan{fill:black;stroke:none;}#mermaid-1777275990952 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-1777275990952 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-1777275990952 .noteText,#mermaid-1777275990952 .noteText&gt;tspan{fill:black;stroke:none;}#mermaid-1777275990952 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-1777275990952 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-1777275990952 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-1777275990952 .actorPopupMenu{position:absolute;}#mermaid-1777275990952 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-1777275990952 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-1777275990952 .actor-man circle,#mermaid-1777275990952 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-1777275990952 :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}</style><g></g><defs><symbol id=\"computer\" width=\"24\" height=\"24\"><path transform=\"scale(.5)\" d=\"M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z\"></path></symbol></defs><defs><symbol id=\"database\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"><path transform=\"scale(.5)\" d=\"M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z\"></path></symbol></defs><defs><symbol id=\"clock\" width=\"24\" height=\"24\"><path transform=\"scale(.5)\" d=\"M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z\"></path></symbol></defs><defs><marker id=\"arrowhead\" refX=\"7.9\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"12\" markerHeight=\"12\" orient=\"auto-start-reverse\"><path d=\"M -1 0 L 10 5 L 0 10 z\"></path></marker></defs><defs><marker id=\"crosshead\" markerWidth=\"15\" markerHeight=\"8\" orient=\"auto\" refX=\"4\" refY=\"4.5\"><path fill=\"none\" stroke=\"#000000\" stroke-width=\"1pt\" d=\"M 1,2 L 6,7 M 6,2 L 1,7\" style=\"stroke-dasharray: 0, 0;\"></path></marker></defs><defs><marker id=\"filled-head\" refX=\"15.5\" refY=\"7\" markerWidth=\"20\" markerHeight=\"28\" orient=\"auto\"><path d=\"M 18,7 L9,13 L14,7 L9,1 Z\"></path></marker></defs><defs><marker id=\"sequencenumber\" refX=\"15\" refY=\"15\" markerWidth=\"60\" markerHeight=\"40\" orient=\"auto\"><circle cx=\"15\" cy=\"15\" r=\"6\"></circle></marker></defs><text x=\"242\" y=\"80\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">POST /api/bookings</text><line x1=\"76\" y1=\"119\" x2=\"408\" y2=\"119\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></line><text x=\"245\" y=\"134\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">booking confirmation + package IDs</text><line x1=\"411\" y1=\"173\" x2=\"79\" y2=\"173\" class=\"messageLine1\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"stroke-dasharray: 3, 3; fill: none;\"></line><text x=\"242\" y=\"188\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">POST /api/redirect-tokens/create</text><line x1=\"76\" y1=\"227\" x2=\"408\" y2=\"227\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></line><text x=\"245\" y=\"242\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">redirect_token (valid 5 min)</text><line x1=\"411\" y1=\"281\" x2=\"79\" y2=\"281\" class=\"messageLine1\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"stroke-dasharray: 3, 3; fill: none;\"></line><text x=\"405\" y=\"296\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">Open WebView with redirect_token</text><line x1=\"76\" y1=\"335\" x2=\"733\" y2=\"335\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></line><text x=\"576\" y=\"350\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">POST /api/webapp/auth/exchange</text><line x1=\"736\" y1=\"389\" x2=\"416\" y2=\"389\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></line><text x=\"573\" y=\"404\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">session JWT</text><line x1=\"413\" y1=\"443\" x2=\"733\" y2=\"443\" class=\"messageLine1\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"stroke-dasharray: 3, 3; fill: none;\"></line><text x=\"576\" y=\"458\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">GET /api/webapp/me/dashboard</text><line x1=\"736\" y1=\"497\" x2=\"416\" y2=\"497\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></line><text x=\"573\" y=\"512\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">user dashboard data</text><line x1=\"413\" y1=\"551\" x2=\"733\" y2=\"551\" class=\"messageLine1\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"stroke-dasharray: 3, 3; fill: none;\"></line><text x=\"738\" y=\"566\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">User claims packages,</text><text x=\"738\" y=\"588\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">installs eSIM, monitors data</text><path d=\"M 738,627 C 798,617 798,657 738,647\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></path></svg></div>"},"children":["sequenceDiagram\n    participant PB as Partner Backend\n    participant API as Hubby API\n    participant WV as Hubby WebView<br/>(in Partner App)\n\n    PB->>API: POST /api/bookings\n    API-->>PB: booking confirmation + package IDs\n\n    PB->>API: POST /api/redirect-tokens/create\n    API-->>PB: redirect_token (valid 5 min)\n\n    PB->>WV: Open WebView with redirect_token\n\n    WV->>API: POST /api/webapp/auth/exchange\n    API-->>WV: session JWT\n\n    WV->>API: GET /api/webapp/me/dashboard\n    API-->>WV: user dashboard data\n\n    WV->>WV: User claims packages,<br/>installs eSIM, monitors data\n"]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"the-full-flow"},"children":["The Full Flow"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-1--create-a-booking"},"children":["Step 1 — Create a Booking"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]}]}," — your backend calls this when a traveler qualifies for a package (e.g., at flight booking time, loyalty reward, or campaign trigger). The Booking entity maps directly to the travel booking you already have — a departure date, one or more destinations, and the bundles (data packages) for each."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"request-fields"},"children":["Request Fields"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Type"},"children":["Type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Required"},"children":["Required"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["departure_date"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["ISO 8601 datetime with timezone (e.g., ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["2026-07-15T14:30:00+02:00"]},"). Including the time and timezone enables precise CRM triggers such as push notifications 2 hours before departure"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["locale"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["WebView language (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["es"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["fr"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["de"]},", etc.). See ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/advanced-topics/supported-locales"},"children":["supported locales"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["custom_branding"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Selects your branded theme. Partners with multiple sub-brands pass the brand key here"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package_specifications"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["array"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["One or more packages to provision"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"package-specification-fields"},"children":["Package Specification Fields"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Type"},"children":["Type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Required"},"children":["Required"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Yes"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Required for WebView integration."]}," Your own identifier for the traveler receiving this package. This is the key that links the booking to the traveler across all subsequent calls — redirect tokens, WebView auth exchange, and sessions. Use your own internal user ID and pass the same value consistently."]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["destination"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["ISO 3166-1 alpha-2 country code (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GR"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["US"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["JP"]},")"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["size"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Data package size (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["1GB"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["3GB"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["5GB"]},")"]}]}]}]}]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Important:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," is ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["required"]}," for the WebView flow. It must be your own stable user identifier, and the same value must be used across all WebView endpoints — bookings, redirect tokens, and the auth exchange. If you are not using the WebView or ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/native-api"},"children":["Native eSIM Integration"]},", do not supply this field — it is ignored in the traditional booking flow and supplying it incorrectly will route the package into the eSIM management flow."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"multi-destination-bookings"},"children":["Multi-Destination Bookings"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A single booking can contain multiple entries in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package_specifications"]},". Hubby automatically optimizes the assignment — for example, a trip covering Greenland, Canada, the US, and Mexico may be fulfilled with a single North America regional package plus individual packages where more cost-effective."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example"},"children":["Example"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"curl --request POST \\\n  'https://api.hubbyesim.com/api/bookings' \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'x-timestamp: 1717689600000' \\\n  --header 'x-signature: YOUR_HMAC_SIGNATURE' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n    \"departure_date\": \"2026-07-15T14:30:00+02:00\",\n    \"locale\": \"es\",\n    \"custom_branding\": \"your-brand\",\n    \"package_specifications\": [\n      {\n        \"external_user_id\": \"partner_user_456\",\n        \"destination\": \"GR\",\n        \"size\": \"1GB\"\n      }\n    ]\n  }'\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"success\": true,\n  \"data\": {\n    \"id\": \"booking_abc\",\n    \"package_specifications\": [\n      {\n        \"external_user_id\": \"partner_user_456\",\n        \"package_id\": \"pkg_xyz\",\n        \"destination\": \"GR\",\n        \"size\": \"1GB\",\n        \"status\": \"provisioned\"\n      }\n    ]\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Note:"]}," ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," is required for the WebView flow. Always supply your own consistent user identifier — it is the key that ties the booking, redirect token, and WebView session together."]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-2--create-a-redirect-token"},"children":["Step 2 — Create a Redirect Token"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/redirect-tokens/create"]}]}," — your backend calls this right before the traveler opens the eSIM section in your app. The response contains a short-lived ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirect_token"]}," that your app uses to open the Hubby WebView."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"request-fields-1"},"children":["Request Fields"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Type"},"children":["Type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Required"},"children":["Required"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Your own user identifier"]}," — the same value you used in the booking's ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package_specifications"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirect_token"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["If you pre-generate the token, pass it here. Otherwise Hubby generates one"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"token-lifetime"},"children":["Token Lifetime"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The redirect token is valid for ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["5 minutes"]},". This prevents URL forwarding and sharing. If the token expires before the traveler opens the WebView, request a fresh one from the same endpoint."]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Important:"]}," Do NOT cache the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirect_token"]},". Generate a new token every time the traveler opens the eSIM section in your app — on every open, on app resume if the WebView was killed by the OS, and if the 5-minute window expires."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-1"},"children":["Example"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"curl --request POST \\\n  'https://api.hubbyesim.com/api/redirect-tokens/create' \\\n  --header 'x-api-key: YOUR_API_KEY' \\\n  --header 'x-timestamp: 1717689600000' \\\n  --header 'x-signature: YOUR_HMAC_SIGNATURE' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n    \"external_user_id\": \"partner_user_456\"\n  }'\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"success\": true,\n  \"data\": {\n    \"redirect_token\": \"1b80dfe9-0202-4151-a26f-ceac52ca3b34\",\n    \"expires_in\": 300\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-3--open-the-webview"},"children":["Step 3 — Open the WebView"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your app opens the Hubby WebView in an in-app browser using the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirect_token"]}," returned in Step 2. Construct the URL as ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://app.hubbyesim.com?t={redirect_token}"]}," and append device information as additional query parameters so the WebView can tailor eSIM installation instructions to the traveler's exact device."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"device-query-parameters"},"children":["Device Query Parameters"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Parameter"},"children":["Parameter"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Type"},"children":["Type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["phone_os"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Operating system (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["iOS"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Android"]},")"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["phone_model"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Device model (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["iPhone 15 Pro"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Samsung Galaxy S24"]},")"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["os_version"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["OS version (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["17.4"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["14"]},")"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["phone_brand"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Device manufacturer (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Apple"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Samsung"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Google"]},")"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All parameters are optional. The WebView also performs its own browser-based device detection, but passing these values from the native app provides more accurate results — especially for device model and brand, which browsers cannot reliably detect."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-2"},"children":["Example"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"header":{"controls":{"copy":{}}},"source":"https://app.hubbyesim.com?t=1b80dfe9-0202-4151-a26f-ceac52ca3b34&phone_os=iOS&phone_model=iPhone%2015%20Pro&os_version=17.4&phone_brand=Apple\n"},"children":[]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Tip:"]}," URL-encode parameter values. These parameters are read client-side by the WebView — they are never sent to the Hubby backend."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"what-the-traveler-sees"},"children":["What the Traveler Sees"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The WebView adapts to the traveler's state:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Traveler has unclaimed packages →"]}," A congratulations screen appears (\"You got 1GB for Greece!\"). The traveler can:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Accept"]}," — starts the eSIM installation flow, tailored to their exact device and OS version"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Skip"]}," — moves to the next unclaimed package"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["After all packages are claimed (or skipped), the traveler sees the data meter."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["No unclaimed packages →"]}," The data meter screen shows:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Active package status and remaining data"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Option to buy more data"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If all packages have expired, a \"Get a package\" prompt"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"session-behaviour"},"children":["Session Behaviour"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Closing the WebView"]}," ends the session. The next time the traveler opens it, your app should generate a new redirect token (Step 2) and re-open."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Auth token persists"]}," across navigations within the same WebView session — no re-authentication while the browser instance is alive."]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["If the OS kills the WebView in the background, generate a new redirect token on app resume."]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"esim-installation-url-handling"},"children":["eSIM Installation URL Handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When the traveler taps \"Install eSIM\" inside the WebView, the web app navigates to a ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["system-level provisioning URL"]},". These look like normal ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://"]}," links but are handled by the OS, not by a browser. A WebView will silently fail to load them unless your native app intercepts and hands them off to the OS."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["URLs the web app navigates to:"]}]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Platform"},"children":["Platform"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"URL"},"children":["URL"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Android"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://esimsetup.android.com/esim_qrcode_provisioning?carddata=LPA:1$<smdp-address>$<matching-id>"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":["iOS"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://esimsetup.apple.com/esim_qrcode_provisioning?carddata=LPA:1$<smdp-address>$<matching-id>"]}]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["carddata"]}," query parameter contains the GSMA LPA activation code in the format ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["LPA:1$<SM-DP+ address>$<matching ID>"]},"."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Why this is needed:"]}," These URLs are not real websites. On Android, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["esimsetup.android.com"]}," is an ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"https://developer.android.com/training/app-links"},"children":["Android App Link"]}," registered by the system eSIM provisioning service — it only works via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["startActivity"]}," with ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ACTION_VIEW"]},". On iOS, ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["esimsetup.apple.com"]}," is handled by the iOS Cellular Setup service — it only works via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UIApplication.open(_:)"]},". If your WebView does not intercept these URLs, the navigation fails silently and the user sees nothing happen."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Your app must intercept these URL patterns and launch them externally:"]}]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"URL Pattern"},"children":["URL Pattern"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Platform"},"children":["Platform"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Action"},"children":["Action"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://esimsetup.android.com/*"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Android"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Launch with OS via Intent / ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["ACTION_VIEW"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["https://esimsetup.apple.com/*"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["iOS"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Launch with OS via ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["UIApplication.open"]}]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["LPA:1$..."]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Both"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Launch externally (GSMA standard scheme)"]}]}]}]}]},{"$$mdtype":"Tag","name":"Tabs","attributes":{},"children":[{"$$mdtype":"Tag","name":"div","attributes":{"label":"Android (Kotlin)"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Override ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["shouldOverrideUrlLoading"]}," in your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["WebViewClient"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"kotlin","header":{"controls":{"copy":{}}},"source":"webView.webViewClient = object : WebViewClient() {\n    override fun shouldOverrideUrlLoading(\n        view: WebView,\n        request: WebResourceRequest\n    ): Boolean {\n        val url = request.url.toString()\n\n        // eSIM provisioning URL — launch with the OS\n        if (url.startsWith(\"https://esimsetup.android.com/\")) {\n            val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))\n            startActivity(intent)\n            return true\n        }\n\n        // Direct LPA activation code\n        if (url.startsWith(\"LPA:\")) {\n            val intent = Intent(Intent.ACTION_VIEW, Uri.parse(url))\n            startActivity(intent)\n            return true\n        }\n\n        return false\n    }\n}\n","lang":"kotlin"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"iOS (Swift)"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Implement ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["decidePolicyFor"]}," in your ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["WKNavigationDelegate"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"swift","header":{"controls":{"copy":{}}},"source":"func webView(\n    _ webView: WKWebView,\n    decidePolicyFor navigationAction: WKNavigationAction,\n    decisionHandler: @escaping (WKNavigationActionPolicy) -> Void\n) {\n    guard let url = navigationAction.request.url else {\n        decisionHandler(.allow)\n        return\n    }\n\n    let urlString = url.absoluteString\n\n    // eSIM provisioning URL — launch with the OS\n    if urlString.hasPrefix(\"https://esimsetup.apple.com/\") {\n        UIApplication.shared.open(url, options: [:], completionHandler: nil)\n        decisionHandler(.cancel)\n        return\n    }\n\n    // Direct LPA activation code\n    if urlString.hasPrefix(\"LPA:\") {\n        UIApplication.shared.open(url, options: [:], completionHandler: nil)\n        decisionHandler(.cancel)\n        return\n    }\n\n    decisionHandler(.allow)\n}\n","lang":"swift"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Add queried URL schemes to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["Info.plist"]}," (optional but recommended):"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"xml","header":{"controls":{"copy":{}}},"source":"<key>LSApplicationQueriesSchemes</key>\n<array>\n    <string>LPA</string>\n</array>\n","lang":"xml"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"Flutter (Dart)"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["webview_flutter"]}," and ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["url_launcher"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"dart","header":{"controls":{"copy":{}}},"source":"_controller = WebViewController()\n  ..setJavaScriptMode(JavaScriptMode.unrestricted)\n  ..setNavigationDelegate(NavigationDelegate(\n    onNavigationRequest: (NavigationRequest request) {\n      final url = request.url;\n\n      // eSIM provisioning URLs — launch with the OS\n      if (url.startsWith('https://esimsetup.android.com/') ||\n          url.startsWith('https://esimsetup.apple.com/')) {\n        launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);\n        return NavigationDecision.prevent;\n      }\n\n      // Direct LPA activation code\n      if (url.startsWith('LPA:')) {\n        launchUrl(Uri.parse(url), mode: LaunchMode.externalApplication);\n        return NavigationDecision.prevent;\n      }\n\n      return NavigationDecision.navigate;\n    },\n  ))\n  ..loadRequest(Uri.parse(webAppUrl));\n","lang":"dart"},"children":[]}]},{"$$mdtype":"Tag","name":"div","attributes":{"label":"React Native"},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Using ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["react-native-webview"]},":"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"tsx","header":{"controls":{"copy":{}}},"source":"<WebView\n  source={{ uri: webAppUrl }}\n  onShouldStartLoadWithRequest={(request) => {\n    const { url } = request;\n\n    // eSIM provisioning URLs — launch with the OS\n    if (url.startsWith('https://esimsetup.android.com/') ||\n        url.startsWith('https://esimsetup.apple.com/')) {\n      Linking.openURL(url);\n      return false;\n    }\n\n    // Direct LPA activation code\n    if (url.startsWith('LPA:')) {\n      Linking.openURL(url);\n      return false;\n    }\n\n    return true;\n  }}\n/>\n","lang":"tsx"},"children":[]}]}]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Testing:"]}," After implementing, create a booking and open the WebView. Tap \"Install eSIM\" — the device's native eSIM provisioning dialog should appear. If nothing happens, check your debug logs for the intercepted URL."]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-4--token-exchange-automatic"},"children":["Step 4 — Token Exchange (automatic)"]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Partners do not call this endpoint. It is documented here for transparency and to help debug WebView network traffic."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When the WebView loads with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirect_token"]},", it automatically calls:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/webapp/auth/exchange"]}]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"redirect_token\": \"1b80dfe9-0202-4151-a26f-ceac52ca3b34\",\n  \"external_user_id\": \"partner_user_456\"\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This exchanges the short-lived redirect token for a session JWT. The JWT is scoped to ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/webapp/"]}," endpoints only — it cannot be used for partner backend calls and your API keys are never exposed to the WebView."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"step-5--dashboard-load-automatic"},"children":["Step 5 — Dashboard Load (automatic)"]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Partners do not call this endpoint. Documented for transparency."]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The WebView uses the session JWT to load the traveler's dashboard:"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /api/webapp/me/dashboard"]}]}]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"curl --request GET \\\n  'https://api.hubbyesim.com/api/webapp/me/dashboard' \\\n  --header 'Authorization: Bearer <session_jwt>' \\\n  --header 'Content-Type: application/json'\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The response includes active packages, data usage, unclaimed packages, and available actions. The WebView renders this into the branded UI."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"how-authentication-works"},"children":["How Authentication Works"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The WebView flow uses two separate auth contexts. They never mix."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"your-backend--hubby-api-hmac-sha256"},"children":["Your Backend → Hubby API (HMAC-SHA256)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["All calls from your backend use HMAC-SHA256 signing. Every request includes:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["x-api-key"]}," — your public API key"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["x-timestamp"]}," — current Unix timestamp in milliseconds"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["x-signature"]}," — HMAC-SHA256 of ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["{timestamp}{METHOD}{path}"]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["This covers ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]},", ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/redirect-tokens/create"]},", and all other partner-facing endpoints. See the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/authentication"},"children":["authentication guide"]}," for implementation details."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"webview--hubby-api-jwt"},"children":["WebView → Hubby API (JWT)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The WebView authenticates with a short-lived JWT obtained through the token exchange (Step 4). This is completely separate from your HMAC credentials — the WebView never has access to your API keys."]},{"$$mdtype":"Tag","name":"Mermaid","attributes":{"data-language":"mermaid","diagramSource":"sequenceDiagram\n    participant PB as Partner Backend\n    participant API as Hubby API\n    participant WV as Hubby WebView\n\n    Note over PB,API: HMAC-SHA256\n    PB->>API: POST /api/redirect-tokens/create\n    API-->>PB: redirect_token\n\n    Note over WV,API: JWT\n    WV->>API: POST /api/webapp/auth/exchange\n    API-->>WV: session JWT\n    WV->>API: GET /api/webapp/me/dashboard\n    API-->>WV: dashboard data\n","diagramHtml":"<div class=\"mermaid\" data-processed=\"true\"><svg id=\"mermaid-1777275990893\" width=\"100%\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" style=\"max-width: 889px;\" viewBox=\"-50 -10 889 599\" role=\"graphics-document document\" aria-roledescription=\"sequence\"><g><rect x=\"639\" y=\"513\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"WV\" rx=\"3\" ry=\"3\" class=\"actor actor-bottom\"></rect><text x=\"714\" y=\"545.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"714\" dy=\"0\">Hubby WebView</tspan></text></g><g><rect x=\"314\" y=\"513\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"API\" rx=\"3\" ry=\"3\" class=\"actor actor-bottom\"></rect><text x=\"389\" y=\"545.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"389\" dy=\"0\">Hubby API</tspan></text></g><g><rect x=\"0\" y=\"513\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"PB\" rx=\"3\" ry=\"3\" class=\"actor actor-bottom\"></rect><text x=\"75\" y=\"545.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"75\" dy=\"0\">Partner Backend</tspan></text></g><g><line id=\"actor2\" x1=\"714\" y1=\"65\" x2=\"714\" y2=\"513\" class=\"actor-line 200\" stroke-width=\"0.5px\" stroke=\"#999\" name=\"WV\"></line><g id=\"root-2\"><rect x=\"639\" y=\"0\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"WV\" rx=\"3\" ry=\"3\" class=\"actor actor-top\"></rect><text x=\"714\" y=\"32.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"714\" dy=\"0\">Hubby WebView</tspan></text></g></g><g><line id=\"actor1\" x1=\"389\" y1=\"65\" x2=\"389\" y2=\"513\" class=\"actor-line 200\" stroke-width=\"0.5px\" stroke=\"#999\" name=\"API\"></line><g id=\"root-1\"><rect x=\"314\" y=\"0\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"API\" rx=\"3\" ry=\"3\" class=\"actor actor-top\"></rect><text x=\"389\" y=\"32.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"389\" dy=\"0\">Hubby API</tspan></text></g></g><g><line id=\"actor0\" x1=\"75\" y1=\"65\" x2=\"75\" y2=\"513\" class=\"actor-line 200\" stroke-width=\"0.5px\" stroke=\"#999\" name=\"PB\"></line><g id=\"root-0\"><rect x=\"0\" y=\"0\" fill=\"#eaeaea\" stroke=\"#666\" width=\"150\" height=\"65\" name=\"PB\" rx=\"3\" ry=\"3\" class=\"actor actor-top\"></rect><text x=\"75\" y=\"32.5\" dominant-baseline=\"central\" alignment-baseline=\"central\" class=\"actor actor-box\" style=\"text-anchor: middle; font-size: 16px; font-weight: 400;\"><tspan x=\"75\" dy=\"0\">Partner Backend</tspan></text></g></g><style>#mermaid-1777275990893{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-1777275990893 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-1777275990893 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-1777275990893 .error-icon{fill:#552222;}#mermaid-1777275990893 .error-text{fill:#552222;stroke:#552222;}#mermaid-1777275990893 .edge-thickness-normal{stroke-width:1px;}#mermaid-1777275990893 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-1777275990893 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-1777275990893 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-1777275990893 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-1777275990893 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-1777275990893 .marker{fill:#333333;stroke:#333333;}#mermaid-1777275990893 .marker.cross{stroke:#333333;}#mermaid-1777275990893 svg{font-family:\"trebuchet ms\",verdana,arial,sans-serif;font-size:16px;}#mermaid-1777275990893 p{margin:0;}#mermaid-1777275990893 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-1777275990893 text.actor&gt;tspan{fill:black;stroke:none;}#mermaid-1777275990893 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-1777275990893 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-1777275990893 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-1777275990893 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-1777275990893 #arrowhead path{fill:#333;stroke:#333;}#mermaid-1777275990893 .sequenceNumber{fill:white;}#mermaid-1777275990893 #sequencenumber{fill:#333;}#mermaid-1777275990893 #crosshead path{fill:#333;stroke:#333;}#mermaid-1777275990893 .messageText{fill:#333;stroke:none;}#mermaid-1777275990893 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-1777275990893 .labelText,#mermaid-1777275990893 .labelText&gt;tspan{fill:black;stroke:none;}#mermaid-1777275990893 .loopText,#mermaid-1777275990893 .loopText&gt;tspan{fill:black;stroke:none;}#mermaid-1777275990893 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-1777275990893 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-1777275990893 .noteText,#mermaid-1777275990893 .noteText&gt;tspan{fill:black;stroke:none;}#mermaid-1777275990893 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-1777275990893 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-1777275990893 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-1777275990893 .actorPopupMenu{position:absolute;}#mermaid-1777275990893 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-1777275990893 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-1777275990893 .actor-man circle,#mermaid-1777275990893 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-1777275990893 :root{--mermaid-font-family:\"trebuchet ms\",verdana,arial,sans-serif;}</style><g></g><defs><symbol id=\"computer\" width=\"24\" height=\"24\"><path transform=\"scale(.5)\" d=\"M2 2v13h20v-13h-20zm18 11h-16v-9h16v9zm-10.228 6l.466-1h3.524l.467 1h-4.457zm14.228 3h-24l2-6h2.104l-1.33 4h18.45l-1.297-4h2.073l2 6zm-5-10h-14v-7h14v7z\"></path></symbol></defs><defs><symbol id=\"database\" fill-rule=\"evenodd\" clip-rule=\"evenodd\"><path transform=\"scale(.5)\" d=\"M12.258.001l.256.004.255.005.253.008.251.01.249.012.247.015.246.016.242.019.241.02.239.023.236.024.233.027.231.028.229.031.225.032.223.034.22.036.217.038.214.04.211.041.208.043.205.045.201.046.198.048.194.05.191.051.187.053.183.054.18.056.175.057.172.059.168.06.163.061.16.063.155.064.15.066.074.033.073.033.071.034.07.034.069.035.068.035.067.035.066.035.064.036.064.036.062.036.06.036.06.037.058.037.058.037.055.038.055.038.053.038.052.038.051.039.05.039.048.039.047.039.045.04.044.04.043.04.041.04.04.041.039.041.037.041.036.041.034.041.033.042.032.042.03.042.029.042.027.042.026.043.024.043.023.043.021.043.02.043.018.044.017.043.015.044.013.044.012.044.011.045.009.044.007.045.006.045.004.045.002.045.001.045v17l-.001.045-.002.045-.004.045-.006.045-.007.045-.009.044-.011.045-.012.044-.013.044-.015.044-.017.043-.018.044-.02.043-.021.043-.023.043-.024.043-.026.043-.027.042-.029.042-.03.042-.032.042-.033.042-.034.041-.036.041-.037.041-.039.041-.04.041-.041.04-.043.04-.044.04-.045.04-.047.039-.048.039-.05.039-.051.039-.052.038-.053.038-.055.038-.055.038-.058.037-.058.037-.06.037-.06.036-.062.036-.064.036-.064.036-.066.035-.067.035-.068.035-.069.035-.07.034-.071.034-.073.033-.074.033-.15.066-.155.064-.16.063-.163.061-.168.06-.172.059-.175.057-.18.056-.183.054-.187.053-.191.051-.194.05-.198.048-.201.046-.205.045-.208.043-.211.041-.214.04-.217.038-.22.036-.223.034-.225.032-.229.031-.231.028-.233.027-.236.024-.239.023-.241.02-.242.019-.246.016-.247.015-.249.012-.251.01-.253.008-.255.005-.256.004-.258.001-.258-.001-.256-.004-.255-.005-.253-.008-.251-.01-.249-.012-.247-.015-.245-.016-.243-.019-.241-.02-.238-.023-.236-.024-.234-.027-.231-.028-.228-.031-.226-.032-.223-.034-.22-.036-.217-.038-.214-.04-.211-.041-.208-.043-.204-.045-.201-.046-.198-.048-.195-.05-.19-.051-.187-.053-.184-.054-.179-.056-.176-.057-.172-.059-.167-.06-.164-.061-.159-.063-.155-.064-.151-.066-.074-.033-.072-.033-.072-.034-.07-.034-.069-.035-.068-.035-.067-.035-.066-.035-.064-.036-.063-.036-.062-.036-.061-.036-.06-.037-.058-.037-.057-.037-.056-.038-.055-.038-.053-.038-.052-.038-.051-.039-.049-.039-.049-.039-.046-.039-.046-.04-.044-.04-.043-.04-.041-.04-.04-.041-.039-.041-.037-.041-.036-.041-.034-.041-.033-.042-.032-.042-.03-.042-.029-.042-.027-.042-.026-.043-.024-.043-.023-.043-.021-.043-.02-.043-.018-.044-.017-.043-.015-.044-.013-.044-.012-.044-.011-.045-.009-.044-.007-.045-.006-.045-.004-.045-.002-.045-.001-.045v-17l.001-.045.002-.045.004-.045.006-.045.007-.045.009-.044.011-.045.012-.044.013-.044.015-.044.017-.043.018-.044.02-.043.021-.043.023-.043.024-.043.026-.043.027-.042.029-.042.03-.042.032-.042.033-.042.034-.041.036-.041.037-.041.039-.041.04-.041.041-.04.043-.04.044-.04.046-.04.046-.039.049-.039.049-.039.051-.039.052-.038.053-.038.055-.038.056-.038.057-.037.058-.037.06-.037.061-.036.062-.036.063-.036.064-.036.066-.035.067-.035.068-.035.069-.035.07-.034.072-.034.072-.033.074-.033.151-.066.155-.064.159-.063.164-.061.167-.06.172-.059.176-.057.179-.056.184-.054.187-.053.19-.051.195-.05.198-.048.201-.046.204-.045.208-.043.211-.041.214-.04.217-.038.22-.036.223-.034.226-.032.228-.031.231-.028.234-.027.236-.024.238-.023.241-.02.243-.019.245-.016.247-.015.249-.012.251-.01.253-.008.255-.005.256-.004.258-.001.258.001zm-9.258 20.499v.01l.001.021.003.021.004.022.005.021.006.022.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.023.018.024.019.024.021.024.022.025.023.024.024.025.052.049.056.05.061.051.066.051.07.051.075.051.079.052.084.052.088.052.092.052.097.052.102.051.105.052.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.048.144.049.147.047.152.047.155.047.16.045.163.045.167.043.171.043.176.041.178.041.183.039.187.039.19.037.194.035.197.035.202.033.204.031.209.03.212.029.216.027.219.025.222.024.226.021.23.02.233.018.236.016.24.015.243.012.246.01.249.008.253.005.256.004.259.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.021.224-.024.22-.026.216-.027.212-.028.21-.031.205-.031.202-.034.198-.034.194-.036.191-.037.187-.039.183-.04.179-.04.175-.042.172-.043.168-.044.163-.045.16-.046.155-.046.152-.047.148-.048.143-.049.139-.049.136-.05.131-.05.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.053.083-.051.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.05.023-.024.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.023.01-.022.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.127l-.077.055-.08.053-.083.054-.085.053-.087.052-.09.052-.093.051-.095.05-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.045-.118.044-.12.043-.122.042-.124.042-.126.041-.128.04-.13.04-.132.038-.134.038-.135.037-.138.037-.139.035-.142.035-.143.034-.144.033-.147.032-.148.031-.15.03-.151.03-.153.029-.154.027-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.01-.179.008-.179.008-.181.006-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.006-.179-.008-.179-.008-.178-.01-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.027-.153-.029-.151-.03-.15-.03-.148-.031-.146-.032-.145-.033-.143-.034-.141-.035-.14-.035-.137-.037-.136-.037-.134-.038-.132-.038-.13-.04-.128-.04-.126-.041-.124-.042-.122-.042-.12-.044-.117-.043-.116-.045-.113-.045-.112-.046-.109-.047-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.05-.093-.052-.09-.051-.087-.052-.085-.053-.083-.054-.08-.054-.077-.054v4.127zm0-5.654v.011l.001.021.003.021.004.021.005.022.006.022.007.022.009.022.01.022.011.023.012.023.013.023.015.024.016.023.017.024.018.024.019.024.021.024.022.024.023.025.024.024.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.052.11.051.114.051.119.052.123.05.127.051.131.05.135.049.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.044.171.042.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.022.23.02.233.018.236.016.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.012.241-.015.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.048.139-.05.136-.049.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.051.051-.049.023-.025.023-.024.021-.025.02-.024.019-.024.018-.024.017-.024.015-.023.014-.023.013-.024.012-.022.01-.023.01-.023.008-.022.006-.022.006-.022.004-.021.004-.022.001-.021.001-.021v-4.139l-.077.054-.08.054-.083.054-.085.052-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.049-.105.048-.106.047-.109.047-.111.046-.114.045-.115.044-.118.044-.12.044-.122.042-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.035-.143.033-.144.033-.147.033-.148.031-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.025-.161.024-.162.023-.163.022-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.011-.178.009-.179.009-.179.007-.181.007-.182.005-.182.004-.184.003-.184.002h-.37l-.184-.002-.184-.003-.182-.004-.182-.005-.181-.007-.179-.007-.179-.009-.178-.009-.176-.011-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.022-.162-.023-.161-.024-.159-.025-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.031-.146-.033-.145-.033-.143-.033-.141-.035-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.04-.126-.041-.124-.042-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.047-.105-.048-.102-.049-.1-.049-.097-.05-.095-.051-.093-.051-.09-.051-.087-.053-.085-.052-.083-.054-.08-.054-.077-.054v4.139zm0-5.666v.011l.001.02.003.022.004.021.005.022.006.021.007.022.009.023.01.022.011.023.012.023.013.023.015.023.016.024.017.024.018.023.019.024.021.025.022.024.023.024.024.025.052.05.056.05.061.05.066.051.07.051.075.052.079.051.084.052.088.052.092.052.097.052.102.052.105.051.11.052.114.051.119.051.123.051.127.05.131.05.135.05.139.049.144.048.147.048.152.047.155.046.16.045.163.045.167.043.171.043.176.042.178.04.183.04.187.038.19.037.194.036.197.034.202.033.204.032.209.03.212.028.216.027.219.025.222.024.226.021.23.02.233.018.236.017.24.014.243.012.246.01.249.008.253.006.256.003.259.001.26-.001.257-.003.254-.006.25-.008.247-.01.244-.013.241-.014.237-.016.233-.018.231-.02.226-.022.224-.024.22-.025.216-.027.212-.029.21-.03.205-.032.202-.033.198-.035.194-.036.191-.037.187-.039.183-.039.179-.041.175-.042.172-.043.168-.044.163-.045.16-.045.155-.047.152-.047.148-.048.143-.049.139-.049.136-.049.131-.051.126-.05.123-.051.118-.052.114-.051.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.052.07-.051.065-.051.06-.051.056-.05.051-.049.023-.025.023-.025.021-.024.02-.024.019-.024.018-.024.017-.024.015-.023.014-.024.013-.023.012-.023.01-.022.01-.023.008-.022.006-.022.006-.022.004-.022.004-.021.001-.021.001-.021v-4.153l-.077.054-.08.054-.083.053-.085.053-.087.053-.09.051-.093.051-.095.051-.097.05-.1.049-.102.048-.105.048-.106.048-.109.046-.111.046-.114.046-.115.044-.118.044-.12.043-.122.043-.124.042-.126.041-.128.04-.13.039-.132.039-.134.038-.135.037-.138.036-.139.036-.142.034-.143.034-.144.033-.147.032-.148.032-.15.03-.151.03-.153.028-.154.028-.156.027-.158.026-.159.024-.161.024-.162.023-.163.023-.165.021-.166.02-.167.019-.169.018-.169.017-.171.016-.173.015-.173.014-.175.013-.175.012-.177.01-.178.01-.179.009-.179.007-.181.006-.182.006-.182.004-.184.003-.184.001-.185.001-.185-.001-.184-.001-.184-.003-.182-.004-.182-.006-.181-.006-.179-.007-.179-.009-.178-.01-.176-.01-.176-.012-.175-.013-.173-.014-.172-.015-.171-.016-.17-.017-.169-.018-.167-.019-.166-.02-.165-.021-.163-.023-.162-.023-.161-.024-.159-.024-.157-.026-.156-.027-.155-.028-.153-.028-.151-.03-.15-.03-.148-.032-.146-.032-.145-.033-.143-.034-.141-.034-.14-.036-.137-.036-.136-.037-.134-.038-.132-.039-.13-.039-.128-.041-.126-.041-.124-.041-.122-.043-.12-.043-.117-.044-.116-.044-.113-.046-.112-.046-.109-.046-.106-.048-.105-.048-.102-.048-.1-.05-.097-.049-.095-.051-.093-.051-.09-.052-.087-.052-.085-.053-.083-.053-.08-.054-.077-.054v4.153zm8.74-8.179l-.257.004-.254.005-.25.008-.247.011-.244.012-.241.014-.237.016-.233.018-.231.021-.226.022-.224.023-.22.026-.216.027-.212.028-.21.031-.205.032-.202.033-.198.034-.194.036-.191.038-.187.038-.183.04-.179.041-.175.042-.172.043-.168.043-.163.045-.16.046-.155.046-.152.048-.148.048-.143.048-.139.049-.136.05-.131.05-.126.051-.123.051-.118.051-.114.052-.11.052-.106.052-.101.052-.096.052-.092.052-.088.052-.083.052-.079.052-.074.051-.07.052-.065.051-.06.05-.056.05-.051.05-.023.025-.023.024-.021.024-.02.025-.019.024-.018.024-.017.023-.015.024-.014.023-.013.023-.012.023-.01.023-.01.022-.008.022-.006.023-.006.021-.004.022-.004.021-.001.021-.001.021.001.021.001.021.004.021.004.022.006.021.006.023.008.022.01.022.01.023.012.023.013.023.014.023.015.024.017.023.018.024.019.024.02.025.021.024.023.024.023.025.051.05.056.05.06.05.065.051.07.052.074.051.079.052.083.052.088.052.092.052.096.052.101.052.106.052.11.052.114.052.118.051.123.051.126.051.131.05.136.05.139.049.143.048.148.048.152.048.155.046.16.046.163.045.168.043.172.043.175.042.179.041.183.04.187.038.191.038.194.036.198.034.202.033.205.032.21.031.212.028.216.027.22.026.224.023.226.022.231.021.233.018.237.016.241.014.244.012.247.011.25.008.254.005.257.004.26.001.26-.001.257-.004.254-.005.25-.008.247-.011.244-.012.241-.014.237-.016.233-.018.231-.021.226-.022.224-.023.22-.026.216-.027.212-.028.21-.031.205-.032.202-.033.198-.034.194-.036.191-.038.187-.038.183-.04.179-.041.175-.042.172-.043.168-.043.163-.045.16-.046.155-.046.152-.048.148-.048.143-.048.139-.049.136-.05.131-.05.126-.051.123-.051.118-.051.114-.052.11-.052.106-.052.101-.052.096-.052.092-.052.088-.052.083-.052.079-.052.074-.051.07-.052.065-.051.06-.05.056-.05.051-.05.023-.025.023-.024.021-.024.02-.025.019-.024.018-.024.017-.023.015-.024.014-.023.013-.023.012-.023.01-.023.01-.022.008-.022.006-.023.006-.021.004-.022.004-.021.001-.021.001-.021-.001-.021-.001-.021-.004-.021-.004-.022-.006-.021-.006-.023-.008-.022-.01-.022-.01-.023-.012-.023-.013-.023-.014-.023-.015-.024-.017-.023-.018-.024-.019-.024-.02-.025-.021-.024-.023-.024-.023-.025-.051-.05-.056-.05-.06-.05-.065-.051-.07-.052-.074-.051-.079-.052-.083-.052-.088-.052-.092-.052-.096-.052-.101-.052-.106-.052-.11-.052-.114-.052-.118-.051-.123-.051-.126-.051-.131-.05-.136-.05-.139-.049-.143-.048-.148-.048-.152-.048-.155-.046-.16-.046-.163-.045-.168-.043-.172-.043-.175-.042-.179-.041-.183-.04-.187-.038-.191-.038-.194-.036-.198-.034-.202-.033-.205-.032-.21-.031-.212-.028-.216-.027-.22-.026-.224-.023-.226-.022-.231-.021-.233-.018-.237-.016-.241-.014-.244-.012-.247-.011-.25-.008-.254-.005-.257-.004-.26-.001-.26.001z\"></path></symbol></defs><defs><symbol id=\"clock\" width=\"24\" height=\"24\"><path transform=\"scale(.5)\" d=\"M12 2c5.514 0 10 4.486 10 10s-4.486 10-10 10-10-4.486-10-10 4.486-10 10-10zm0-2c-6.627 0-12 5.373-12 12s5.373 12 12 12 12-5.373 12-12-5.373-12-12-12zm5.848 12.459c.202.038.202.333.001.372-1.907.361-6.045 1.111-6.547 1.111-.719 0-1.301-.582-1.301-1.301 0-.512.77-5.447 1.125-7.445.034-.192.312-.181.343.014l.985 6.238 5.394 1.011z\"></path></symbol></defs><defs><marker id=\"arrowhead\" refX=\"7.9\" refY=\"5\" markerUnits=\"userSpaceOnUse\" markerWidth=\"12\" markerHeight=\"12\" orient=\"auto-start-reverse\"><path d=\"M -1 0 L 10 5 L 0 10 z\"></path></marker></defs><defs><marker id=\"crosshead\" markerWidth=\"15\" markerHeight=\"8\" orient=\"auto\" refX=\"4\" refY=\"4.5\"><path fill=\"none\" stroke=\"#000000\" stroke-width=\"1pt\" d=\"M 1,2 L 6,7 M 6,2 L 1,7\" style=\"stroke-dasharray: 0, 0;\"></path></marker></defs><defs><marker id=\"filled-head\" refX=\"15.5\" refY=\"7\" markerWidth=\"20\" markerHeight=\"28\" orient=\"auto\"><path d=\"M 18,7 L9,13 L14,7 L9,1 Z\"></path></marker></defs><defs><marker id=\"sequencenumber\" refX=\"15\" refY=\"15\" markerWidth=\"60\" markerHeight=\"40\" orient=\"auto\"><circle cx=\"15\" cy=\"15\" r=\"6\"></circle></marker></defs><g><rect x=\"50\" y=\"75\" fill=\"#EDF2AE\" stroke=\"#666\" width=\"364\" height=\"42\" class=\"note\"></rect><text x=\"232\" y=\"80\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"noteText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\"><tspan x=\"232\">HMAC-SHA256</tspan></text></g><g><rect x=\"364\" y=\"235\" fill=\"#EDF2AE\" stroke=\"#666\" width=\"375\" height=\"42\" class=\"note\"></rect><text x=\"552\" y=\"240\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"noteText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\"><tspan x=\"552\">JWT</tspan></text></g><text x=\"231\" y=\"132\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">POST /api/redirect-tokens/create</text><line x1=\"76\" y1=\"171\" x2=\"385\" y2=\"171\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></line><text x=\"234\" y=\"186\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">redirect_token</text><line x1=\"388\" y1=\"225\" x2=\"79\" y2=\"225\" class=\"messageLine1\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"stroke-dasharray: 3, 3; fill: none;\"></line><text x=\"553\" y=\"292\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">POST /api/webapp/auth/exchange</text><line x1=\"713\" y1=\"331\" x2=\"393\" y2=\"331\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></line><text x=\"550\" y=\"346\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">session JWT</text><line x1=\"390\" y1=\"385\" x2=\"710\" y2=\"385\" class=\"messageLine1\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"stroke-dasharray: 3, 3; fill: none;\"></line><text x=\"553\" y=\"400\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">GET /api/webapp/me/dashboard</text><line x1=\"713\" y1=\"439\" x2=\"393\" y2=\"439\" class=\"messageLine0\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"fill: none;\"></line><text x=\"550\" y=\"454\" text-anchor=\"middle\" dominant-baseline=\"middle\" alignment-baseline=\"middle\" class=\"messageText\" dy=\"1em\" style=\"font-size: 16px; font-weight: 400;\">dashboard data</text><line x1=\"390\" y1=\"493\" x2=\"710\" y2=\"493\" class=\"messageLine1\" stroke-width=\"2\" stroke=\"none\" marker-end=\"url(#arrowhead)\" style=\"stroke-dasharray: 3, 3; fill: none;\"></line></svg></div>"},"children":["sequenceDiagram\n    participant PB as Partner Backend\n    participant API as Hubby API\n    participant WV as Hubby WebView\n\n    Note over PB,API: HMAC-SHA256\n    PB->>API: POST /api/redirect-tokens/create\n    API-->>PB: redirect_token\n\n    Note over WV,API: JWT\n    WV->>API: POST /api/webapp/auth/exchange\n    API-->>WV: session JWT\n    WV->>API: GET /api/webapp/me/dashboard\n    API-->>WV: dashboard data\n"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"security-properties"},"children":["Security Properties"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Time-limited tokens"]}," — the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirect_token"]}," expires in 5 minutes, preventing forwarding/sharing"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["No PII in the URL"]}," — the WebView URL contains only the opaque ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["redirect_token"]}," and optional device metadata"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Client-side device info"]}," — device parameters are read by the WebView client-side and never sent to the Hubby backend"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Scoped JWT"]}," — valid only for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/webapp/"]}," endpoints, tied to the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"identifier-reference"},"children":["Identifier Reference"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["A single identifier — ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," — ties everything together across the WebView flow."]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Endpoint"},"children":["Endpoint"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"How external_user_id is used"},"children":["How ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," is used"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]}," → ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package_specifications[]"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Links each package to a specific traveler"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/redirect-tokens/create"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Ties the WebView session to the traveler"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/webapp/auth/exchange"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Validates the traveler matches the redirect token"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/webapp/refresh-esim"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Identifies which user to assign the fresh eSIM to"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use your own internal user ID as the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," and pass the same value consistently across all three endpoints. This field is required for the WebView flow — the redirect token and auth exchange will fail without it."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"refresh-universal-esim"},"children":["Refresh Universal eSIM"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/webapp/refresh-esim"]}]}," — assigns a fresh universal eSIM to a user. If the user already has a universal eSIM, it is replaced. If they don't have one yet, a new eSIM is provisioned and assigned."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use this to pre-provision an eSIM before the traveler opens the WebView, or to replace a problematic eSIM with a fresh one."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Authentication:"]}," Bearer JWT from ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/webapp/auth/exchange"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"request-fields-2"},"children":["Request Fields"]},{"$$mdtype":"Tag","name":"div","attributes":{"className":"md-table-wrapper"},"children":[{"$$mdtype":"Tag","name":"table","attributes":{"className":"md"},"children":[{"$$mdtype":"Tag","name":"thead","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Field"},"children":["Field"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Type"},"children":["Type"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Required"},"children":["Required"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Description"},"children":["Description"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["string"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Yes"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your own user identifier — the same value used in bookings and redirect tokens"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":4,"id":"example-3"},"children":["Example"]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"bash","header":{"controls":{"copy":{}}},"source":"curl --request POST \\\n  'https://api.hubbyesim.com/api/webapp/refresh-esim' \\\n  --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIs...' \\\n  --header 'Content-Type: application/json' \\\n  --data '{\n    \"external_user_id\": \"partner_user_456\"\n  }'\n","lang":"bash"},"children":[]},{"$$mdtype":"Tag","name":"CodeBlock","attributes":{"data-language":"json","header":{"controls":{"copy":{}}},"source":"{\n  \"success\": true,\n  \"data\": {\n    \"iccid\": \"8901234567890123456\",\n    \"qr\": \"LPA:1$smdp.example.com$ACTIVATION-CODE\",\n    \"status\": \"RELEASED\"\n  }\n}\n","lang":"json"},"children":[]},{"$$mdtype":"Tag","name":"blockquote","attributes":{},"children":[{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Note:"]}," This endpoint is idempotent in intent — calling it always results in a fresh eSIM assigned to the user, whether or not they had one before. The previous eSIM (if any) is replaced."]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-comes-next"},"children":["What Comes Next"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The WebView gets you live fast. Once it's running, you can progressively enhance the experience:"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"communication--conversion-weeks-24"},"children":["Communication & Conversion (Weeks 2–4)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/advanced-topics/webhooks"},"children":["webhooks"]}," to receive real-time events and map them to push notifications:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["booking.within_cutoff"]}]}," — departure is 7 days away, send an installation reminder"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["booking.about_to_depart"]}]}," — 2 hours before flight (requires time + timezone in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["departure_date"]},"), last-chance install prompt"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["esim.installed"]}]}," / ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["esim.removed"]}]}," — track installation state"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package.activated"]}]}," — traveler connected at destination"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package.usage.20_percent"]}]}," / ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package.usage.50_percent"]}]}," / ",{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package.usage.80_percent"]}]}," — per-package usage milestones (data consumed or duration elapsed), drive top-up revenue at 80%"]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"branding--segmentation"},"children":["Branding & Segmentation"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Use ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/advanced-topics/branding"},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["custom_branding"]}]}," to run separate branded themes per sub-brand. Different customer segments can receive different package sizes (e.g., premium members get 3GB, standard members get 1GB) by varying ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["size"]}," in ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package_specifications"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"zero-rated-traffic"},"children":["Zero-Rated Traffic"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Ensure your core app functionality (boarding passes, booking management, payments) remains accessible to travelers even when their data package is depleted. Provide your critical IP ranges to Hubby and we configure zero-rated traffic policies."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"native-api-optional"},"children":["Native API (Optional)"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["For partners who want to go beyond the WebView, Hubby offers a Native API covering packages, provisioning, installation instructions, usage reporting, and event streams. The WebView and Native API coexist — many partners start with the WebView and selectively move high-traffic features (data meter, top-up) to native over time."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"troubleshooting"},"children":["Troubleshooting"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"token-expired-error-in-webview"},"children":["\"Token expired\" error in WebView"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The redirect token was not opened within 5 minutes. Generate a new token and re-open."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"invalid-external_user_id-error"},"children":["\"Invalid external_user_id\" error"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," in the token exchange does not match the one used when creating the redirect token. Ensure your app passes the same identifier consistently."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"nothing-happens-when-traveler-taps-install-esim"},"children":["Nothing happens when traveler taps \"Install eSIM\""]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your WebView is loading the provisioning URL (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["esimsetup.android.com"]}," or ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["esimsetup.apple.com"]},") as a webpage instead of launching it externally. Implement the URL interception described in ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"#esim-installation-url-handling"},"children":["eSIM Installation URL Handling"]},"."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"webview-shows-a-blank-screen"},"children":["WebView shows a blank screen"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Check your network inspector for a failed ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/webapp/auth/exchange"]}," call. Common causes:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Redirect token already consumed (tokens are single-use)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["Network timeout during the exchange"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":["WebView security settings blocking the request (ensure JavaScript is enabled and cross-origin requests are allowed for ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["app.hubbyesim.com"]},")"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"quick-start-checklist"},"children":["Quick-Start Checklist"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["To go live, your team provides:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," User identifier format (your internal user ID that becomes ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]},")"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Brand assets per sub-brand (logos, colors, copy)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Required locales for the WebView"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Customer segment → package size mapping"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Technical point of contact"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Hubby provides:"]}]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," API keys (staging + production), per sub-brand if needed"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Branded WebView configured per sub-brand"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Staging environment with all endpoints"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"input","attributes":{"checked":false,"type":"checkbox","readOnly":true},"children":[]}," Integration support"]}]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"related"},"children":["Related"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/apis/v2_0_0/openapi"},"children":["API Reference — WebView endpoints"]}," — full OpenAPI spec for redirect tokens, token exchange, and dashboard"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/authentication"},"children":["Authentication guide"]}," — HMAC-SHA256 setup"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/advanced-topics/multi-destination"},"children":["Multi-destination bookings"]}," — advanced booking patterns"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/advanced-topics/branding"},"children":["Branding"]}," — configure branded themes"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/advanced-topics/webhooks"},"children":["Webhooks"]}," — real-time event delivery"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/advanced-topics/supported-locales"},"children":["Supported locales"]}," — available WebView languages"]}]}]},"headings":[{"value":"Hubby WebView","id":"hubby-webview","depth":1},{"value":"What You Build vs. What Hubby Handles","id":"what-you-build-vs.-what-hubby-handles","depth":2},{"value":"Architecture","id":"architecture","depth":2},{"value":"The Full Flow","id":"the-full-flow","depth":2},{"value":"Step 1 — Create a Booking","id":"step-1--create-a-booking","depth":3},{"value":"Request Fields","id":"request-fields","depth":4},{"value":"Package Specification Fields","id":"package-specification-fields","depth":4},{"value":"Multi-Destination Bookings","id":"multi-destination-bookings","depth":4},{"value":"Example","id":"example","depth":4},{"value":"Step 2 — Create a Redirect Token","id":"step-2--create-a-redirect-token","depth":3},{"value":"Request Fields","id":"request-fields-1","depth":4},{"value":"Token Lifetime","id":"token-lifetime","depth":4},{"value":"Example","id":"example-1","depth":4},{"value":"Step 3 — Open the WebView","id":"step-3--open-the-webview","depth":3},{"value":"Device Query Parameters","id":"device-query-parameters","depth":4},{"value":"Example","id":"example-2","depth":4},{"value":"What the Traveler Sees","id":"what-the-traveler-sees","depth":4},{"value":"Session Behaviour","id":"session-behaviour","depth":4},{"value":"eSIM Installation URL Handling","id":"esim-installation-url-handling","depth":4},{"value":"Step 4 — Token Exchange (automatic)","id":"step-4--token-exchange-automatic","depth":3},{"value":"Step 5 — Dashboard Load (automatic)","id":"step-5--dashboard-load-automatic","depth":3},{"value":"How Authentication Works","id":"how-authentication-works","depth":2},{"value":"Your Backend → Hubby API (HMAC-SHA256)","id":"your-backend--hubby-api-hmac-sha256","depth":3},{"value":"WebView → Hubby API (JWT)","id":"webview--hubby-api-jwt","depth":3},{"value":"Security Properties","id":"security-properties","depth":3},{"value":"Identifier Reference","id":"identifier-reference","depth":2},{"value":"Refresh Universal eSIM","id":"refresh-universal-esim","depth":2},{"value":"Request Fields","id":"request-fields-2","depth":4},{"value":"Example","id":"example-3","depth":4},{"value":"What Comes Next","id":"what-comes-next","depth":2},{"value":"Communication & Conversion (Weeks 2–4)","id":"communication--conversion-weeks-24","depth":3},{"value":"Branding & Segmentation","id":"branding--segmentation","depth":3},{"value":"Zero-Rated Traffic","id":"zero-rated-traffic","depth":3},{"value":"Native API (Optional)","id":"native-api-optional","depth":3},{"value":"Troubleshooting","id":"troubleshooting","depth":2},{"value":"\"Token expired\" error in WebView","id":"token-expired-error-in-webview","depth":3},{"value":"\"Invalid external_user_id\" error","id":"invalid-external_user_id-error","depth":3},{"value":"Nothing happens when traveler taps \"Install eSIM\"","id":"nothing-happens-when-traveler-taps-install-esim","depth":3},{"value":"WebView shows a blank screen","id":"webview-shows-a-blank-screen","depth":3},{"value":"Quick-Start Checklist","id":"quick-start-checklist","depth":2},{"value":"Related","id":"related","depth":2}],"frontmatter":{"title":"Hubby WebView","description":"How to embed the Hubby web app in your mobile app — from first booking to data meter, with the full API flow explained","seo":{"title":"Hubby WebView"}},"lastModified":"2026-04-26T18:00:55.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/webview","userData":{"isAuthenticated":false,"teams":["anonymous"]}}