{"templateId":"markdown","sharedDataIds":{"sidebar":"sidebar-sidebars.yaml"},"props":{"metadata":{"markdoc":{"tagList":[]},"type":"markdown"},"seo":{"title":"Migrating from WebView to Native","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":"migrating-from-webview-to-native"},"children":["Migrating from WebView to Native"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["If you're already live with the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/webview"},"children":["Hubby WebView"]},", you're closer to a ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/native-api"},"children":["Native eSIM Integration"]}," than you might think. The two integrations share the same booking API, the same authentication, the same webhooks, and the same underlying eSIM infrastructure. The only difference is what your app does ",{"$$mdtype":"Tag","name":"em","attributes":{},"children":["after"]}," a booking is created."]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Frankly, the technical side of this migration is usually not the difficult part. The real work is in designing your native UI screens — the data meter, installation flow, package selection, and top-up experience. The API migration itself is minimal."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"how-similar-are-they"},"children":["How Similar Are They?"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Very. Here's the full picture:"]},{"$$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":"Concern"},"children":["Concern"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"WebView"},"children":["WebView"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Native"},"children":["Native"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"Changes?"},"children":["Changes?"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Create booking"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Identical call"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Authentication"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["HMAC-SHA256"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["HMAC-SHA256"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No change"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Required on every booking"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Required on every booking"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No change"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Package provisioning"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Automatic"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Automatic"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No change"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Multi-destination optimization"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Automatic"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Automatic"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No change"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Universal eSIM lifecycle"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Managed by Hubby"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Managed by Hubby"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No change"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Webhooks"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Same events"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Same events"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["No change"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Traveler sees packages"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Hubby WebView UI"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your native UI"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["You build it"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["eSIM installation"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Hubby WebView guides"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your UI + ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/native/instructions"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["You build it"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Data meter"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Hubby WebView UI"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your UI + ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/native/user-dashboard"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["You build it"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Top-up purchase"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Hubby WebView store"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Your UI + ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["You handle payment"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Package activation"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Automatic in WebView"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /native/redeem-package"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["New call"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Device compatibility"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Handled by WebView"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /native/device-compatibility"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["New call (optional)"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The entire backend integration — booking, auth, webhooks — stays the same. You're swapping out the frontend layer: instead of opening a WebView URL, you call a few ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["/native/*"]}," endpoints and render the results yourself."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"what-youre-actually-changing"},"children":["What You're Actually Changing"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"removing-redirect-tokens--webview"},"children":["Removing: redirect tokens + WebView"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In the WebView flow, after creating a booking your backend creates a redirect token (",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/redirect-tokens/create"]},") and your app uses that token to open the Hubby WebView in an in-app browser. You can drop both of these."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"adding-three-new-endpoints"},"children":["Adding: three new endpoints"]},{"$$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":"Purpose"},"children":["Purpose"]},{"$$mdtype":"Tag","name":"th","attributes":{"data-label":"When to call"},"children":["When to call"]}]}]},{"$$mdtype":"Tag","name":"tbody","attributes":{},"children":[{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /api/native/user-dashboard"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Returns the full traveler state — eSIM, packages, queues, data usage"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Every time the user opens the eSIM section"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/native/redeem-package"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Activates a pending package onto the traveler's eSIM"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When the user taps \"Redeem\" or \"Activate\""]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/native/instructions"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Returns device-specific eSIM installation steps"]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["When the user needs to install their eSIM"]}]}]}]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Optional:"]},{"$$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":"Purpose"},"children":["Purpose"]}]}]},{"$$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/native/device-compatibility"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["Check if a specific device supports eSIM"]}]},{"$$mdtype":"Tag","name":"tr","attributes":{},"children":[{"$$mdtype":"Tag","name":"td","attributes":{},"children":[{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /api/native/device-compatibility"]}]},{"$$mdtype":"Tag","name":"td","attributes":{},"children":["List all known compatible devices"]}]}]}]}]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"adding-payment-handling"},"children":["Adding: payment handling"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["In the WebView, Hubby manages the top-up purchase UI. In the Native integration, you are the Merchant of Record — you handle the payment in your app, then call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]}," to provision the package. Hubby provides B2B net rates and recommended B2C prices via the package catalog."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"migration-steps"},"children":["Migration Steps"]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"1.-keep-your-bookings-exactly-as-they-are"},"children":["1. Keep your bookings exactly as they are"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Your existing ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]}," calls already include ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," — that's required for both WebView and Native. Don't change anything about how you create bookings. The same booking endpoint, same payload, same response."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"2.-build-your-native-dashboard-screen"},"children":["2. Build your native dashboard screen"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["GET /api/native/user-dashboard?external_user_id=..."]}," and render the traveler's state. This single endpoint returns everything: user info, eSIM credentials, package queues, active packages, and data usage. See the ",{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/native-api#step-2--fetch-user-dashboard"},"children":["Native eSIM Integration guide"]}," for the full response structure and rendering logic."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"3.-add-package-redemption"},"children":["3. Add package redemption"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["When a traveler has unredeemed package queues, call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/native/redeem-package"]}," with the ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["package_queue_id"]},". The response includes the updated eSIM state so you can refresh the UI without a second dashboard call."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"4.-add-installation-instructions"},"children":["4. Add installation instructions"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/native/instructions"]}," with the traveler's device info. Hubby returns branded, device-specific steps — no need to maintain installation content in your app. This endpoint adapts to the device model, OS version, eSIM state, and locale."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"5.-handle-top-up-payments"},"children":["5. Handle top-up payments"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Replace the WebView's built-in purchase flow with your own. When a traveler wants more data, process the payment through your PSP, then call ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/bookings"]}," with the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]},". The new package queues onto their existing eSIM automatically."]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":3,"id":"6.-stop-creating-redirect-tokens"},"children":["6. Stop creating redirect tokens"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["Once your native screens are live, you no longer need ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["POST /api/redirect-tokens/create"]},". Remove the redirect token creation and the WebView open from your app."]},{"$$mdtype":"Tag","name":"hr","attributes":{},"children":[]},{"$$mdtype":"Tag","name":"Heading","attributes":{"level":2,"id":"mixing-webview-and-native"},"children":["Mixing WebView and Native"]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["You don't have to migrate everything at once. WebView and Native can coexist for the same partner — they share the same ",{"$$mdtype":"Tag","name":"code","attributes":{},"children":["external_user_id"]}," and the same booking infrastructure. Common patterns:"]},{"$$mdtype":"Tag","name":"ul","attributes":{},"children":[{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Native data meter, WebView for everything else"]}," — move only the most-viewed screen to native while keeping the rest in the WebView"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Native for returning travelers, WebView for new users"]}," — new users get the guided WebView experience; returning users get the faster native flow"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"strong","attributes":{},"children":["Gradual rollout"]}," — build native screens for a subset of users while keeping the WebView as the fallback"]}]},{"$$mdtype":"Tag","name":"p","attributes":{},"children":["The decision is entirely in your app's UI layer. You can switch individual users between WebView and Native at any time."]},{"$$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":"/guides/native-api"},"children":["Native eSIM Integration guide"]}," — complete native flow reference"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/webview"},"children":["Hubby WebView guide"]}," — complete WebView flow reference"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/authentication"},"children":["Authentication guide"]}," — HMAC-SHA256 setup (same for both)"]},{"$$mdtype":"Tag","name":"li","attributes":{},"children":[{"$$mdtype":"Tag","name":"a","attributes":{"href":"/guides/advanced-topics/webhooks"},"children":["Webhooks"]}," — event catalog (shared across both integration modes)"]}]}]},"headings":[{"value":"Migrating from WebView to Native","id":"migrating-from-webview-to-native","depth":1},{"value":"How Similar Are They?","id":"how-similar-are-they","depth":2},{"value":"What You're Actually Changing","id":"what-youre-actually-changing","depth":2},{"value":"Removing: redirect tokens + WebView","id":"removing-redirect-tokens--webview","depth":3},{"value":"Adding: three new endpoints","id":"adding-three-new-endpoints","depth":3},{"value":"Adding: payment handling","id":"adding-payment-handling","depth":3},{"value":"Migration Steps","id":"migration-steps","depth":2},{"value":"1. Keep your bookings exactly as they are","id":"1.-keep-your-bookings-exactly-as-they-are","depth":3},{"value":"2. Build your native dashboard screen","id":"2.-build-your-native-dashboard-screen","depth":3},{"value":"3. Add package redemption","id":"3.-add-package-redemption","depth":3},{"value":"4. Add installation instructions","id":"4.-add-installation-instructions","depth":3},{"value":"5. Handle top-up payments","id":"5.-handle-top-up-payments","depth":3},{"value":"6. Stop creating redirect tokens","id":"6.-stop-creating-redirect-tokens","depth":3},{"value":"Mixing WebView and Native","id":"mixing-webview-and-native","depth":2},{"value":"Related","id":"related","depth":2}],"frontmatter":{"title":"Migrating from WebView to Native","description":"Moving from the Hubby WebView to the Native eSIM Integration — a straightforward swap of what happens after the booking","seo":{"title":"Migrating from WebView to Native"}},"lastModified":"2026-04-26T18:00:55.000Z","pagePropGetterError":{"message":"","name":""}},"slug":"/guides/advanced-topics/webview-to-native-migration","userData":{"isAuthenticated":false,"teams":["anonymous"]}}