Changelog
All notable changes to this project will be documented in this file.
Partner API (core)
[5.20.0] - 2026-10-29
Added
storebooking source (5.20.0): a booking'ssourcecan now bestore, a guest purchase in your embedded store (<store id>.hubbyesim.app). You read these bookings back through your booking endpoints, as before.sourceis an open enum (see the Native eSIM Integration guide, section 10, "Versioning"), so code with adefaultbranch already handles the new value. No shape changes, and no new refusals.@hubbyesim/sdk2.7.0 speaks Partner API 5.20.0.BookingSourcegainsstore.
[5.19.0] - 2026-10-26
Not additive
A new Partner API minor is additive, except for the changes its changelog entry names. These are the changes 5.19.0 names: after each one, a request that succeeded before can be refused. Read them before you upgrade.
- A starter issued and then cancelled counts toward the Starter limit (5.19.0): a traveler who holds two such starters for one destination from you is refused a third.
POST /v1/bookingsand the package-specification updates answer422validation_failedonpackage_type. The issue call answers422validation_failedonexternal_user_id, or409starter_cap_exceeded. - A starter upgraded to another package type counts toward the Starter limit (5.19.0): the refusals are the same as above.
Changed
- The Starter limit is two per destination (5.19.0): a traveler can have at most two Starter packages per destination from you. Before, the limit was one live Starter package per traveler. A second starter for the same traveler and destination, a starter for another destination, and a starter for a traveler whose other starters came from another Partner are now accepted. An update that moves a starter to a destination that already holds two is refused. The single package-specification update declares its
422. The Native eSIM Integration guide (section 4, "Starter") states the rule. @hubbyesim/sdk2.6.0 speaks Partner API 5.19.0, and so takes in 5.18.0 too.getCompatibleDevicestakes an optional filter object before the request options:getCompatibleDevices({ brand: 'Samsung' }). A call that passedRequestOptionsas the first argument now passes them second:getCompatibleDevices({}, { signal }). New types:DeviceCompatibilityStatus,DeviceCompatibilityDevice,SupportedDevice,DeviceCompatibilityListFiltersandInstallInstructionApnSetup.
[5.18.0] - 2026-10-26
Not additive
A new Partner API minor is additive, except for the changes its changelog entry names. These are the changes 5.18.0 names: after each one, a value you already read can change. Read them before you upgrade.
is_compatibleisfalsefor a phone that is not on the list (5.18.0):POST /v1/device-compatibilityansweredis_compatible: truefor every device. It now answerstrueonly whenstatusissupported.- The install instructions come from the Hubby web app (5.18.0):
GET /v1/esims/{iccid}/instructionsreturns the copy of the web app's guided setup.min_os_versionis removed from every install set.- The
on_arrivalorder can be different for each family: on Samsung and Xiaomi,mobile_datacomes beforeroaming. Find a section byid, not by position. - On Xiaomi,
one_tap.install_linkisnull: that phone has no one-tap install, and the one-tap steps are the manual steps. - The iPhone
manualsection is localized and has a clip, as on Android. - The copy exists in English, German, Spanish and Swedish. Any other
localegets English, andlocalestill echoes the locale you asked for. esim_labelis your Partner name followed byeSIM. A visual identity no longer has an effect on it, and theHubby eSIMfallback is gone.- The Android families are listed
pixel,samsung,xiaomi(before:samsung,pixel,xiaomi). Find a family byfamily, not by position.
Added
- Device compatibility is a real lookup (5.18.0):
POST /v1/device-compatibilityaddsstatus(supported,unsupportedorunknown),note(regional limits, ornull) anddevice(the matchedbrand,name,modelandyear, ornullforunknown). The match is on brand + device name only.GET /v1/device-compatibilitylists the Supported devices, ordered by brand, then name, with an optionalbrandfilter; before, the list was always empty. The Native eSIM Integration guide (section 6, "Device compatibility") shows both calls. - APN setup in the install instructions (5.18.0): every install set has
apn. Pixel, Samsung and Xiaomi carry{apn, title, clip_url, steps}, the steps to add the access point name by hand for an eSIM that has signal but no internet. The iPhone hasnull.
[5.17.0]
Not additive
A new Partner API minor is additive, except for the changes its changelog entry names. These are the changes 5.17.0 names: after each one, a request that succeeded before can be refused, or a value you already read can change. Read them before you upgrade.
- The catalog reads follow your destination list (5.17.0): when Hubby set up a destination list for your account,
GET /v1/destinations,GET /v1/destinations/{destination},GET /v1/destinations/{destination}/bundlesandGET /v1/bundlesanswer only the destinations on it, the same set your bookings accept. A destination outside the list answers404not_foundon the single reads. With no list, every active destination is answered, as before. destinationmust match exactly (5.17.0):POST /v1/bookingsand the package-specification updates accept the ISO alpha-2 or alpha-3 code, a region's code or the English name, in any letter case. A translated name, a typo or any other value answers422. A specification update whosedestinationmatches nothing answers422; before, it removed the destination from the item.- A repeat after a cancel books a new booking (5.17.0): a cancelled booking no longer holds its
external_referenceanddepart_at. The same pair afterDELETE /v1/bookings/{id}makes a new booking; before, it answered the cancelled booking. A read by reference answers the newest booking. - A
GETignores theIdempotency-Key(5.17.0): nothing is stored and nothing is replayed, and aGETnever answers409idempotency_key_in_use.POST,PATCHandDELETEkeep the key. - A spent issue key stays spent for the life of the item (5.17.0): after a terminate, the key that issued the package answers
409idempotency_key_spentalso after 24 hours. Issue again with a new key. - An end by Hubby or the provider returns the item to
queued(5.17.0): when Hubby or the network provider ends a package you issued before it activated, the item returns toqueuedand the issue key is spent, as after your own terminate. Read the item'sstateand issue again with a new key. An item the traveler redeemed in the Hubby app does not change. POST /v1/redirect-tokensanswers503and409(5.17.0): while Hubby's previous platform cannot answer, the call answers503bridge_unavailablewithRetry-After: 30, and nothing is created; before, it answered a bare500. A record from the previous platform that cannot be imported answers409legacy_graph_not_importable. Retrying gives the same answer; contact Hubby. The operation also declares422validation_failed.- A Native account always books a destination (5.17.0): for an account with
end_customer_channel: partner_app,force_destinationlessis nevertrue; Hubby refuses the combination. A package specification with neitherdestinationnorbundle_idis refused at booking:POST /v1/bookingsanswers422validation_failedonpackage_specifications.N.destination, and the legacy/apibooking call refuses it at booking too. The issue answers422destination_requiredonly for an item booked without a destination: that happens only whileforce_destinationlessistrue(never on a Native account) or when Hubby books the item for you. - A Native account's webhook endpoint gets the default signed body (webhook contract): for an account with
end_customer_channel: partner_app, Hubby refuses an endpoint with the flat body, with a payload template or without a secret, and ignores a flat body or template stored before. - A Native account's booking events carry no
codeoruuid(webhook contract): for an account withend_customer_channel: partner_app,booking.createdandbooking.cancelledcarry each item as{id}. Other accounts keepcodeanduuid. - Every webhook destination field sends the legacy code (webhook contract): on the package and top-up events,
booking.createdpackages[].destination,destinations[]anddestination_details[].iso3, a country is its ISO alpha-3 code (NLD) and a region is its code (EU,XCA). A region line is no longer missing frombooking.created. A multi-country booking from the legacy API can also sendXMS,XMD,XUD,XJK,XUMandXSI, besidesEU,XN,XA,XS,OC,AF,XCAandXME. - A data entry's validity is the end of its queue (5.17.0): on
GET /v1/esims/{iccid}/usage, a data entry with a running package and a waiting package has avalid_untildate (before:null), andremaining_secondsincludes the remainder of the running package. An entry with only running packages does not change.
Added
- One answer shape for the package-specification updates (5.17.0):
PATCH /v1/bookings/{bookingId}/package-specificationsandPATCH /v1/bookings/{bookingId}/package-specifications/{uuid}always answer{updated_count, skipped_count}.skipped_countis0when nothing was skipped and on the single-item call.uuidis a plainstring. - Declared refusals (5.17.0): the issue call declares
422destination_requiredandno_free_esim_available,409provisioning_target_changedandpackage_queue_not_redeemable, and a500that is safe to retry with the sameIdempotency-Key. The single package-specification update declares400package_specification_already_redeemed. The presigned upload's409carriescodeupload_already_exists, and the upload declares its422and its429withRetry-After.GET /v1/bookingsandPOST /v1/redirect-tokensdeclare422validation_failed. X-Hubby-Call-Idon every response (5.17.0): the reference declares the header on every response of every operation, and its introduction names the answers that carry none (a refusal before routing).- Reference details for generated clients (5.17.0): the
iso3filter onGET /v1/destinationsis declared. The requestpackage_typelistsdata_limited,data-limited,starterandunlimited.Bundle.typeuses thePackageTypelist, which has three values:data_limited,starterandunlimited. A nullable field that points to a schema keeps its description, so a generated client keeps the comment.
Changed
- The create-booking schema drops five refused fields (5.17.0):
departure_date,return_date,custom_branding,package_specifications[].esim_typeandpackage_specifications[].expires_atare no longer inCreateBookingRequest. The API has refused them with422since 5.0.0 and still does. - Reference corrections (5.17.0):
CreateBookingRequest.datais a free object, stored and never returned, not a list of strings.communication_optionsis nullable and itschannelsis optional on both booking bodies.date_of_birthis a date, not a date-time. TheGET /v1/bookingsfiltersdepart_at,created_at,departure_fromanddeparture_toare dates (YYYY-MM-DD). No wire change. - Descriptions tell the truth (5.17.0): every other change is a description written for a Partner. The webhook text in the reference and the Native eSIM Integration guide agree: Hubby sends one signature, a secret change is a hard cutover, retries last about 3.4 hours,
package.first_usagefires at 10 MB of use, andesim.location_changearrives 15 to 75 minutes after the attach. No wire change. @hubbyesim/sdk2.5.0 speaks Partner API 5.17.0. Its README and types name the changes above.PackageSpecificationUpdateResponseis one shape withskipped_count, andCreateBookingRequestno longer carries the five refused fields. AGETanswered503legacy_booking_unavailableorinstall_instructions_unavailableis retried, afterRetry-Afterwhen the answer carries one; aPOST,PATCHorDELETEanswered503is not repeated, andbridge_unavailableis not retried. The README error table adds502package_termination_refused,503install_instructions_unavailable,503legacy_booking_unavailable,503bridge_unavailable,409legacy_graph_not_importableand422idempotency_key_reused, and says that a secret change is a hard cutover.
[5.16.0] - 2026-10-19
Added
- Idempotency on every write operation that honours it (5.16.0): the reference declares the optional
Idempotency-Keyheader, the409idempotency_key_in_usewithRetry-After, the422idempotency_key_reused, andIdempotent-Replayed: trueon a replayed success, on thePOST,PATCHandDELETEoperations that accept the key. AGETignores the key: nothing is stored and nothing is replayed, and the reference declares none of this on aGET. Where an operation already listed a409or a422, its body is now one of two shapes (anyOf): for example, the422ofPOST /v1/bookingsis the validation body or{"message", "code": "idempotency_key_reused"}. Branch oncode. iso2,iso3andslugonGET /v1/destinations/{destination}(5.16.0): the single-destination read carries the same codes as the list. Its schema has the stable nameDestinationDetail(before:DestinationResource). The admin fieldstier,is_active,sort_order,click_count,created_at,updated_at,created_byandupdated_byare described as internal: do not build on them.- "Set up by Hubby for your account" in the Native eSIM Integration guide: the settings only Hubby sets (
end_customer_channel,package_strategy,force_destinationless, the default eSIM label, emails to your travelers) and how to check them withGET /v1/me. The guide also states the package order on one eSIM, all rate limits (including presigned upload and analytics), that no device compatibility check exists yet, and how the instruction language falls back.
Changed
- The package-specifications update is two operations (5.16.0):
PATCH /v1/bookings/{bookingId}/package-specificationschanges every item not yet issued, andPATCH /v1/bookings/{bookingId}/package-specifications/{uuid}changes one item.uuidis the item'sidinBooking.items. The behaviour does not change. - Descriptions tell the truth (5.16.0):
communication_optionsand its channels are stored and returned; they do not control Hubby's messages. Hubby emails a traveler only when Hubby has turned on emails for your account, by agreement, and a date change then moves the pre-departure emails. The instructionslocaleandesim_labelfall back from the query to your latest booking that issued a package on the eSIM, then your defaults, thenen-USandHubby eSIM. The eleven internalBundlefields read "Internal; not for Partner use; do not build on it." No wire change. @hubbyesim/sdk2.4.0 speaks Partner API 5.16.0.updatePackageSpecificationscalls the published path without an itemuuid. TheDestinationDetailtype is new;DestinationResourceis a deprecated alias of it. A generated error body is a union where the reference lists two shapes. The shipped types andsigning-vectors.jsoncarry only Partner-facing text.- The webhooks page holds only the contract you implement (webhook contract, no API version): events, set-up, delivery and retries, envelope, headers and signature, and one field table per event. Every delivery attempt is signed again with the time it is sent, so a retry stays inside your timestamp tolerance. The
x-hubby-signatureheader can hold severalsha256=values; one match is enough. - Legacy guides grouped: the legacy-only guides, use cases and tutorials are in the Legacy API group of the sidebar, each with the legacy banner. Their URLs do not change. The legacy Authentication guide says that legacy keys expire after 5 years.
- Webhook package events name their own booking (webhook contract, no API version): on
package.activated,package.first_usageandpackage.usage.*,booking_idis now the reference of the booking that bought the package, ornullwhen that booking has none. For a top-up it is the top-up's booking; before, it was the booking the eSIM was first claimed with.package.terminatedalready named its own booking.
[5.15.0] - 2026-10-19
Added
- Operating facts in the Native eSIM Integration guide: the default rate limits per Partner (issue 30 per minute;
GET /v1/esims/{iccid}andGET /v1/esims/{iccid}/usagewithrefresh=trueshare 60 per minute; reads withoutrefreshhave no limit), whenis_cancellableis true for a booking with nodepart_at, why the top-up rule is in your app and not in the API, and which keys to use: a legacy integration keeps callingapi.hubbyesim.comwith its legacy keys, and the legacy backend forwards those calls to core; to call core directly, use the keys Hubby creates for you on core. The FAQ says that API keys do not expire unless Hubby sets an expiry on the key.
Changed
- Booking semantics, stated once (5.15.0):
itemsis required on every booking read in the reference.BookingItem.statusis deprecated; readstate. The reference and the Native eSIM Integration guide (sections 4 and 8) now state theexternal_referencerule (unique per Partner anddepart_at; the same pair returns the existing booking; never merged), theGET /v1/mesettings that refuse abundle_idwith422, whensizeandpackage_durationare required, how a bookinglocalesets the instruction language, and which read answers which item state. No behaviour changes. - Region codes and the sellable catalog (5.15.0): a region item's
destinationis the region's code (EU,XA,XN,XS,OCiniso2;XCA,XRC,XMEiniso3), the same codeGET /v1/destinationslists, so you can map every booking item back to the catalog.GET /v1/bundlesandGET /v1/destinations/{destination}/bundlesanswer only sellable bundles (active, visible and priced for you). The internal bundle fields (label,provider,package_template,partner,traffic_policy,is_active,is_visible,priority,deleted_at,created_by,updated_by) are described as internal: do not build on them. Read the throttle of an unlimited bundle infair_use_throttle. The Native eSIM Integration guide (section 3) shows the daily ETag sync, which@hubbyesim/sdk2.3.0 does withgetBundles({ etag }): an unchanged catalog resolves to{ notModified: true, etag }instead of an error. No wire change. @hubbyesim/sdk2.3.0 speaks Partner API 5.15.0. 2.3.0 is no longer on npm (unpublished on 2026-10-19); install 2.4.0 or later.createBooking(input, { idempotencyKey })takes your ownIdempotency-Key, so a retry after a crash between booking and saving does not book twice.Booking.itemsis required in the types. The README documents every method.- Webhook
remaining_dayscounts the validity left (webhook contract, no API version): on thepackage.usage.*events it is the calendar days from today to activation plus the package's duration, never below 0, andnullbefore activation. Before, it counted the days toexpires_at, the activation deadline. - Webhook
package.activatedcarrieselapsed_daysandremaining_days(webhook contract, no API version): at activationelapsed_daysis0andremaining_daysis the package's whole duration in calendar days.remaining_daysisnullfor a package with no duration. - The Partner reference is titled "Hubby Partner API" (5.15.0). Before, the generated document was titled "Hubby". Some operation summaries are rewritten to describe what the operation does for you. No wire change.
- Webhook
package.terminatedcarries your reference asbooking_id(webhook contract, no API version), as every other package event does.booking_referencekeeps the same value. Hubby's own booking id is no longer sent on this event. - Webhook
booking_idis your reference on every event (webhook contract, no API version):package_queue.claimed,promo_code.redeemedandupgrade_offer.purchasednow send yourexternal_referenceasbooking_id, ornullwhen the booking has none. Hubby's own booking id is no longer sent on these events. - Legacy pages grouped: the Quickstart and the Authentication Guide describe the legacy API on
api.hubbyesim.com. They are now in the Legacy API group of the sidebar, and each starts with a banner that points to the Native eSIM Integration guide. - The Native eSIM Integration guide no longer promises a Postman collection. The OpenAPI document is the published contract.
[5.14.0] - 2026-10-19
Added
- eSIM usage per destination (Partner API 5.14.0,
@hubbyesim/sdk2.2.0getEsimUsage):GET /v1/esims/{iccid}/usageanswers what the traveler can still use, oneDestinationUsageentry per destination, newest first, withdestination,is_unlimited,total_bytes,used_bytes,remaining_bytes,valid_until,remaining_seconds,package_idsandsynced_at. Packages for one destination add up into one entry; packages bought in the Hubby app count too. The Native eSIM Integration guide shows how to draw one card per entry. destinationon every package ofGET /v1/esims/{iccid}(5.14.0): aDestinationSummary(id,name,type,iso2,iso3). A bundle'sdestinationin the catalog is the same object and gainsnameandtype.GET /v1/destinationsandGET /v1/destinations/{destination}in the reference under the Native eSIM Integration tag, with theDestination,DestinationResourceandDestinationSummaryschemas. Today: both operations are in the Partner API 5.x (core) reference under itsDestinationtag, and the single-read schema isDestinationDetail(since 5.16.0); the document has no Native eSIM Integration tag.
Changed
- Response enums are open (5.14.0): a minor release may add a value; handle one you do not know. A breaking change ships as a new URL major, and
/v1is kept indefinitely. - Native reference corrections: an item
statecan beunavailable; the issue call can answer409starter_cap_exceededand422no_bundle_resolved;communication_options.channelstakesEMAIL,WHATSAPP,PUSH_NOTIFICATIONandSMS; errors use the{"message", "code"}body; and the guide showsGET /v1/destinationsas{ countries, regions }, not wrapped indata.
[5.13.0] - 2026-10-19
Added
valid_untilon the issued package and on every package ofGET /v1/esims/{iccid}(5.13.0): when the package stops working, activation plus its validity.nulluntil the package activates.
Changed
expires_atis the activation deadline (5.13.0): the latest moment the package can still be activated, not when it ends. The value is unchanged; usevalid_untilfor the end.data_remaining_bytesis0on an ended package (5.13.0),expiredorterminated. It staysnullon unlimited.GET /v1/esims/{iccid}/instructionsanswers for every eSIMGET /v1/esims/{iccid}answers for (5.13.0), also after a terminate. Language and eSIM label come from your latest booking that issued a package on the eSIM, else your defaults, elseHubby eSIManden-US. Cache the copy for up to a week. An unsupportedlocaleis422.{destination}accepts an id, an ISO alpha-2 or alpha-3 code, or the English name (5.13.0), in any letter case.- A
404not_foundanswers the messageNot found.(5.13.0). Branch oncode. GET /v1/bundlesis fast (5.13.0): use it for a daily sync, revalidated with itsETag.
[5.12.0] - 2026-10-19
Added
- A
codeon every refusal (5.12.0): every4xxanswers{"message", "code"}. New codes:unauthenticated,timestamp_out_of_window,not_found,item_has_no_package,method_not_allowed,malformed_query_string,validation_failed,rate_limited. Existing codes are unchanged. The reference now lists the codes each Native operation answers. Idempotent-Replayed: true(5.12.0) on every replayed answer of a request sent with anIdempotency-Key.
Changed
- A terminate spends the issue key (5.12.0): after
DELETE /v1/bookings/{booking}/items/{item}/package, theIdempotency-Keythat issued the package answers409idempotency_key_spentand issues nothing. Issue again with a new key.
[5.11.0] - 2026-10-19
Added
- Native eSIM Integration is now server-to-server (Partner API 5.11.0): your backend books, issues the eSIM and receives the install material (LPA string, SM-DP+ address, matching id, one-tap links for iOS and Android), terminates before first use, reads status and usage, and fetches per-OS installation instructions. No traveler session and no Hubby app. Guide: Native eSIM Integration. Reference: the Native eSIM Integration tag —
GET /v1/bundles,GET /v1/destinations/{destination}/bundles,POST|GET|DELETE /v1/bookings/{booking}/items/{item}/package,GET /v1/esims/{iccid},GET /v1/esims/{iccid}/instructions. - Core booking operations in the reference:
POST|GET /v1/bookingsandGET|PATCH|DELETE /v1/bookings/{id}under the Native eSIM Integration tag, with theBooking,BookingItemandCreateBookingRequestschemas, so a client generated from the document can complete the booking-to-issue flow. The legacy/bookingsoperations are unchanged. Every operation under that tag now declares theHmacV1security scheme (seconds timestamp, six-line canonical string), separate from the legacy millisecond scheme ofapi.hubbyesim.com. prices.retailandprices.neton every bundle, andbundle_idon a package specification to book an exact product.is_cancellableon every booking read andstateon every booking item (queued,redeemed,installed,activated,expired,terminated,cancelled).- New webhook event
package.terminated. - Those operations now live in the Partner API 5.x (core) reference. The Native eSIM Integration tag does not exist there: the operations are grouped by resource as
Booking,BookingItemPackage,Esim,Destination,Bundle,CurrentPartner,RedirectTokenandAnalytics. TheHmacV1scheme is published there as thepartnerKey,partnerSignatureandpartnerTimestampsecurity schemes.
Removed
- The legacy
/native/user-dashboard,/native/instructions,/native/device-compatibilityand/native/redeem-packageoperations are no longer documented; the server-to-server calls above replace them.
Legacy API
[Unreleased]
Added
- Webhook events:
external_user_idon every event payload, so a receiver can route an event to the traveler without a lookup. package.activatedandtopup.completed:package_typeandduration_days— the package's type (data-limited,time-limited,unlimited,starter) and its total validity in days, so an unlimited package can be told apart and priced from the event alone.sizeis unchanged and keeps its meaning: for unlimited packages it is the fair-use cap the package was provisioned with (e.g.100GB), never the stringUnlimited, and it is the same value for every duration we sell. Both fields are always present, explicitlynullwhen we cannot resolve them, and carry the same names and meanings as onpackage.usage.*.esim_installedon the two departure-reminder events, so a partner can send "install now" to travelers who have not installed and "you're set" to those who have.- CSV bucket import:
package_quantitycolumn — optional column on the CSV Upload Integration; replicates the row's package specification on the booking (whole number1–20, default1), granting one promo code per replica. Rows with an invalid value are rejected. Multiple different package specifications per row remain unsupported. booking.createdwebhook:packagesarray — one entry per granted package specification (destination,size,package_type,package_duration), not deduplicated: a booking created withpackage_quantity: 3carries three identical entries, one per promo code granted. The existingdestinationsfield stays deduplicated for backwards compatibility — usepackagesto count what was granted.- Classic eSIM grants: New per-spec
esim_type: 'classic' | 'universal'field onPOST /bookings, alongside a per-specemailuser-key (parallel toexternal_user_id) and anexpires_atfield for bounding classic-grant redemption windows. Classic grants surface in the native app via three new Firebase callable functions (list_classic_package_queues,set_classic_package_queue_destination,claim_classic_package_queue). - New schema fields:
package_specifications[].esim_type,package_specifications[].email,package_specifications[].expires_at.BookingResponse.package_queues[].esim_typeis returned so partners can correlate which surface each queue redeems against. - New webhook event
classic_package_queue.claimed— fires when a traveler claims a classic-eSIM grant via the native app. Opt-in viawebhook_settings.events.classic_package_queue_claimed. Payload:queue_id,booking_id,esim_iccid,user_id,partner_id,is_top_up. - New guide: Classic eSIM Grants.
Changed
package.purchasednow covers web app purchases: the event fires for a traveler's first purchase of a destination via the Hubby app or web app (previously native app only). Subsequent purchases for a destination the traveler already has continue to firetopup.completed, so you receive exactly one event per purchase.package_specifications[].external_user_iddescription updated — partners can now identify the User via eitherexternal_user_id(existing) oremail(new) on a per-spec basis.POST /redirect-tokens/createnow acceptsemailas an alternative toexternal_user_id(supply either;external_user_idwins when both are sent). The email path resolves the traveler by email scoped to your partner; the returned token is always keyed on the traveler'sexternal_user_id(assigned automatically if the user — e.g. a classic-grant/email-only traveler — does not have one yet), so the token exchange and WebView session are unchanged.departure_dateis now server-defaulted to the current date when any spec isesim_type: 'classic'and the partner omits it (skeletal Booking for non-travel grants).
Removed
external_user_idis no longer returned at the root of thePOST /bookingsresponse. It was ambiguous (nullfor email-keyed bookings, only the first traveler for multi-traveler bookings). Per-traveler identity is available on thepackage_queues[]fan-out via each entry'suuid. Breaking for any integrator that read the rootexternal_user_idfrom the booking response.
Deprecated
time-limitedpackage type: Thetime-limitedpackage_typeis deprecated and should not be used for new integrations. To offer a fixed data allowance that expires after a set period, use adata-limitedpackage with a shortpackage_durationinstead. Existing integrations continue to work; the type may be removed in a future API version.
[2.1.0] - 2026-03-23
Added
- Destinations API: New endpoints for retrieving destination information
GET /destinations— List all available destinations (countries and regions) with localized names, ISO3 codes, and metadataGET /destinations/{id}— Get a single destination by ID, including its available data bundles (packages)
- New schemas:
DestinationResponse,DestinationDetailResponse,DestinationBundleResponse
Removed
- Countries endpoints:
GET /countries,GET /countries/packages, andGET /countries/{country}/packageshave been removed. Use the new Destinations API instead.
Changed
- Native API tag renamed to Native Integration API for clarity
[1.3.2] - 2026-01-22
Added
- Brand Support: New
custom_brandingfield for booking requests and responses- Allows partners to set a specific visual style for the app experience
- Brand identifier must correspond to a configuration that exists in the Hubby platform
- Contact support to set up custom branding for your organization
- Departure Location: New
departure_locationfield for booking requests and responses- Capture where travelers are departing from (airport code, city name, or address)
- Provides additional context for the booking
[1.3.1] - 2025-10-27
Added
- Promo Code Claiming: New feature to share claim links instead of promo codes directly
- Added
uuidandclaim_urlfields to promo code responses - New public endpoint
POST /api/promo-codes/claim/{uuid}for claiming promo codes with email capture - Claim URLs are only included when bookings don't have an email address
- Immediate email delivery of promo codes upon claiming
- Perfect for events, marketing campaigns, and lead capture
- Added
- Promo Code Retrieval: New endpoint
GET /api/promo-codes/{id}for retrieving promo code details- Partners can fetch their promo codes with full metadata
- Includes RBAC authorization for organization-level access control
- Enhanced Promo Code Documentation: Added comprehensive guide on promo code claiming feature
Changed
- Promo code response schema now includes additional metadata fields:
iso3,package_type,package_duration
[1.3.0] - 2025-07-27
Added
- Package Type Support: Added support for multiple package types in booking requests
package_typeparameter with options:starter,data-limited,unlimited,time-limitedpackage_durationparameter to specify package duration in days- Default values:
data-limitedfor package type, 365 days for data-limited packages, 2 days for starter and time-limited packages
- Enhanced Package Documentation: Added comprehensive documentation explaining the differences between package types
- Starter packages: Small data allowance for short duration, ideal for trials (default: 2 days)
- Data-limited packages: Traditional packages with specific data allowance (default: 365 days)
- Unlimited packages: Unrestricted data usage with fair use policy
- Time-limited packages: Fixed data allowance with time constraint for full-speed access
- Clarification that top-ups are always data-limited packages
Changed
- API Version: Bumped the version to v1.3.0
- Default Package Type: Data-limited packages are now the primary focus and default option
[1.2.0] - 2025-05-12
Added
- Endpoints added for in app integration The first endpoints for in-app integration have been added.
- External ID Support: Added optional
external_idproperty to bookings for better integration with external systems.
Changed
- Destinationless bookings A booking no longer requires a destination to be specified, the destination can now be picked by the end user.
- Bumped the version to v1.2.0
[1.1.0] - 2025-03-16
Added
- HMAC Auth: HMAC Authentication is now the default for this API
- Regen promo codes: Added the option to regenerate codes.
Changed
- Enhanced Entity Details: All models now includes additional metadata fields, such as
created_byandupdated_at, to provide better context for each..
Fixed
- Time Format Consistency: Standardized all time-related fields to use ISO 8601 format, ensuring consistency across the API.
[1.0.0] - 2023-02-15
Initial Release
- Launched the Hubby eSIM API with core features including creating a booking and fetching packages.