Elements
Terudo Elements reference. The five drop-in elements (destination-picker, plans, trip-offer, booking-banner, esim-status), loading, options, callbacks, styling, sessions, checkout, test mode, CSP.
Elements are pieces of Terudo's eSIM shop that render inside your own page: no iframe, your font, your colours. The traveller chooses a plan in your page and pays on Terudo's hosted checkout, where Terudo is the seller (commission model). One script, one publishable key.
Load the script
<script src="https://terudo.com/elements/v1.js" data-key="pk_live_…" data-locale="fr" defer></script>
Script attributes:
| Attribute | Meaning |
|---|---|
data-key |
Your publishable key (pk_live_…, pk_test_…, or the demo key pk_test_terudo_demo_public). With it, the script creates window.terudo and mounts every element marked data-terudo once the page is ready. |
data-locale |
fr, en, de, es, it, pt, zh, ar or hi. Default: the page's <html lang>, then fr. |
data-session |
A client_token from an element session (see Sessions). |
Never put a secret key (sk_…) in a page.
Two ways to mount
Declarative: any element with data-terudo="<name>" and its options as data-* attributes (camelCase options become kebab-case: returnUrl → data-return-url, esimId → data-esim-id, plansInto → data-plans-into).
<div data-terudo="trip-offer" data-destination="JP" data-start="2027-04-02" data-end="2027-04-16" data-profile="heavy"></div>
Elements added to the page later (single-page apps) are mounted by calling terudo.autoMount() (or terudo.autoMount(containerElement)). An element is mounted once; it carries data-terudo-mounted afterwards.
JavaScript: create an instance and mount where you want. Callbacks are only available this way.
const terudo = Terudo({
key: 'pk_live_…',
locale: 'en',
session: clientToken, // optional, from POST /element_sessions
appearance: { color: '#0a5b8a', onColor: '#ffffff', radius: '10px', font: 'inherit' },
});
const offer = terudo.mount('trip-offer', '#esim-offer', {
destination: 'MA', start: '2026-12-03', end: '2026-12-09', profile: 'normal',
email: '[email protected]', returnUrl: 'https://www.your-agency.example/bookings/48213',
onCheckout(order) { analytics.track('esim_checkout', { order: order.order_id }); },
onError(error) { console.warn(error.code, error.message); },
});
offer.update({ start: '2026-12-04' }); // re-renders with new options
Terudo(config) returns { mount(name, target, options), autoMount(scope?), api(path, options), locale, key, origin, elements }. target is a CSS selector or a DOM element; mount empties it first. mount returns { host, update(options) }.
The elements
destination-picker
The destinations of the catalogue, each with its "from" price.
| Option | Type | |
|---|---|---|
title |
string | Heading. Default "Choose your destination". |
onSelect(code, plan) |
function | Called when a destination is picked, with its code and cheapest plan. |
plansInto |
selector or element | Mounts plans for the picked destination there. |
plans
Every plan of one destination, cheapest first, each with its price and a button that asks the traveller's email and opens the checkout.
| Option | Type | |
|---|---|---|
destination |
string, required | ISO code (MA) or region (EU-35). |
days |
integer 1–30 | Adds daily plans of that length. |
email, returnUrl, onSelect(plan), onCheckout(order), onError(error) |
See Checkout and Callbacks. |
trip-offer
Destination and dates in, the recommended plan out (the cheapest that covers the stay plus one buffer day), the other plans a click away. The piece for a visa approval, an itinerary or a trip page.
| Option | Type | |
|---|---|---|
destination |
string, required | |
start, end |
YYYY-MM-DD, required |
Arrival and departure. 60 days at most. |
profile |
light | normal | heavy |
Estimated use: 0.5, 1 or 2 GB a day. Default normal. |
title |
string | Replaces "Your trip: dates". |
email, returnUrl, onSelect, onCheckout, onError |
booking-banner
One line for a booking confirmation: the recommended plan and its price, with a button that opens into the full trip-offer in place.
| Option | Type | |
|---|---|---|
destination, start, end, profile |
As trip-offer. |
|
title, subtitle, cta |
string | Override the banner's texts and the button label. |
onOpen(quote) |
function | Called when the traveller opens the offer. |
email, returnUrl, onCheckout, onError |
esim-status
The traveller's eSIM inside your own customer area: state, data used, install buttons while not installed, validity, link to Terudo's full eSIM page.
| Option | Type | |
|---|---|---|
esimId |
string, required | The esim.id of the order (API) or the token in the traveller's eSIM page link. |
pageUrl |
false |
Hides the link to the full page. |
onLoad(esim) |
function | Called with the eSIM data (no activation code: that stays server-side). |
States shown: preparing, not_installed, active, used_up, ended, suspended, deleted, refunded.
Checkout
The traveller never pays in your page. After choosing a plan they give their email (unless you passed email), the element creates a commission order (POST /public/checkout) and sends the browser to checkout_url on terudo.com. There the traveller accepts Terudo's terms and pays in their currency; the eSIM arrives by email right after payment. Then they are sent to returnUrl:
- kept when its origin is one of the sites listed on your publishable key, or when it comes from an element session;
- otherwise ignored, and the traveller stays on Terudo's confirmation page.
onCheckout(order) runs just before the redirect, with { object: "checkout", order_id, checkout_url, status }. Return false to stop the redirect and handle order.checkout_url yourself (open it in a new tab, a webview, …).
Checkout from a page is limited to 30 orders an hour per IP address.
Callbacks
| Callback | Elements | Called with |
|---|---|---|
onSelect |
destination-picker: (code, plan); plans, trip-offer: (plan) |
The choice |
onCheckout |
plans, trip-offer, booking-banner | The order, before redirecting. false stops the redirect. |
onOpen |
booking-banner | The quote |
onLoad |
esim-status | The eSIM |
onError |
all | An Error with message (shown to the traveller too), code and status |
Styling
Elements inherit the page's font and render in a .tdo container. Set the brand with appearance or CSS variables on the host element:
| Variable | appearance key |
|
|---|---|---|
--tdo-color |
color |
Buttons, selected tiles, links |
--tdo-on |
onColor |
Text on the colour |
--tdo-radius |
radius |
Corners |
--tdo-font |
font |
Font family (default: inherit) |
Elements are responsive and accessible (buttons, ARIA states, progress bar for usage). Test keys show a small "Test" badge.
Sessions
Without a session, an element shows public prices to anyone and asks the traveller for their email. An element session, created by your server with your secret key, signs what the page may not decide on its own:
curl -X POST https://terudo.com/api/partner/v1/element_sessions \
-H "Authorization: Bearer sk_live_…" -H "Content-Type: application/json" \
-d '{
"discount_percent": 10,
"reference": "visa-48213",
"client_email": "[email protected]",
"trip": { "destination": "MA", "start_date": "2026-12-03", "end_date": "2026-12-09", "profile": "normal" },
"return_url": "https://www.your-agency.example/bookings/48213",
"locale": "fr",
"metadata": { "booking_id": "48213" }
}'
# → { "object": "element_session", "client_token": "…", "expires_at": "…", "session": { … } }
discount_percent: client discount 0–15 (default 5), taken from your commission.reference: your booking or file id; the order carries it, and webhooks with it.client_email,return_url,locale,trip,metadata: prefilled and trusted.- Your member rate applies when your account has it.
Pass client_token as data-session on the script or session in Terudo({...}). It lasts two hours: create it when you render the page.
Test mode
pk_test_… keys work exactly like live ones but create sandbox sales: the pay page simulates the payment, the eSIM is not a real one, nothing is billed. The demo key pk_test_terudo_demo_public shows real data but refuses checkout (demo_key). See Testing.
Content Security Policy
Allow script-src https://terudo.com, connect-src https://terudo.com and img-src https://terudo.com.
Errors
A failed element shows a short message in place (in the element's language) and calls onError. Common codes: unauthorized (key unknown or revoked), forbidden (page origin not listed on the key), invalid_trip (dates), unknown_plan, demo_key (checkout with the demo key), rate_limited.
Raw calls
terudo.api(path, { method, query, body }) calls the public routes with your key (and session): destinations, plans, quotes, checkout, esims/<id>. It returns a promise of the JSON. Useful to build your own interface on Terudo's data; the checkout still happens on terudo.com.