Save to Mobile Itinerary
Link reference
What the button's link carries. One Base64url-encoded parameter holds your referral ID and one booking, a flight or a hotel stay.
The link
The link has a single query parameter, t. Its value is your JSON note encoded in Base64url, and everything travels in it, including your referral ID.
https://app.voyani.com/ota/open?t={BASE64_PAYLOAD}| Parameter | Value | Meaning |
|---|---|---|
| t | {BASE64_PAYLOAD} | Your referral ID and the booking, as one JSON note encoded in Base64url. |
How you build t
t is Base64url-encoded JSON. You produce its value in three steps.
- Write the booking note. For each booking, build the JSON on this page: the schema version, your referral ID, the booking reference and type, the time of the tap, and the booking itself.
- Base64url-encode it. Encode the note's UTF-8 bytes as Base64, then make it URL-safe: + becomes -, / becomes _, and trailing = signs are dropped. Standard Base64 with = padding is accepted too.
- Pass the result as t. Put the encoded value in the link as the single query parameter t. The button and the email both use that one value.
Worked example
The minimum hotel payload, from note to link.
{"v":1,"partnerReferralId":"OTA-7K3QZ9M2XA","bookingReference":"HX88213","bookingType":"hotel","referredAt":"2026-11-06T09:00:00Z","destination":{"city":"Lisbon","countryCode":"PT"},"hotel":{"name":"Example Lisbon Hotel","checkInLocal":"2026-12-11T15:00:00","checkOutLocal":"2026-12-17T11:00:00"}}eyJ2IjoxLCJwYXJ0bmVyUmVmZXJyYWxJZCI6Ik9UQS03SzNRWjlNMlhBIiwiYm9va2luZ1JlZmVyZW5jZSI6IkhYODgyMTMiLCJib29raW5nVHlwZSI6ImhvdGVsIiwicmVmZXJyZWRBdCI6IjIwMjYtMTEtMDZUMDk6MDA6MDBaIiwiZGVzdGluYXRpb24iOnsiY2l0eSI6Ikxpc2JvbiIsImNvdW50cnlDb2RlIjoiUFQifSwiaG90ZWwiOnsibmFtZSI6IkV4YW1wbGUgTGlzYm9uIEhvdGVsIiwiY2hlY2tJbkxvY2FsIjoiMjAyNi0xMi0xMVQxNTowMDowMCIsImNoZWNrT3V0TG9jYWwiOiIyMDI2LTEyLTE3VDExOjAwOjAwIn19https://app.voyani.com/ota/open?t=eyJ2IjoxLCJwYXJ0bmVyUmVmZXJyYWxJZCI6Ik9UQS03SzNRWjlNMlhBIiwiYm9va2luZ1JlZmVyZW5jZSI6IkhYODgyMTMiLCJib29raW5nVHlwZSI6ImhvdGVsIiwicmVmZXJyZWRBdCI6IjIwMjYtMTEtMDZUMDk6MDA6MDBaIiwiZGVzdGluYXRpb24iOnsiY2l0eSI6Ikxpc2JvbiIsImNvdW50cnlDb2RlIjoiUFQifSwiaG90ZWwiOnsibmFtZSI6IkV4YW1wbGUgTGlzYm9uIEhvdGVsIiwiY2hlY2tJbkxvY2FsIjoiMjAyNi0xMi0xMVQxNTowMDowMCIsImNoZWNrT3V0TG9jYWwiOiIyMDI2LTEyLTE3VDExOjAwOjAwIn19Booking types
bookingType tells Voyani what you booked: flight with flightSegments, or hotel with hotel. One link carries one booking, and both types share the same required fields and rules.
- FlightDraft specOne flight booking and its segments, with bookingType set to flight.
- HotelDraft specOne hotel stay, with bookingType set to hotel.
Flight payload
Draft specOne flight booking and its segments, with bookingType set to flight.
{
"v": 1,
"partnerReferralId": "OTA-7K3QZ9M2XA",
"bookingReference": "AB12CD",
"bookingType": "flight",
"referredAt": "2026-10-24T14:22:10Z",
"destination": {
"city": "Lisbon",
"countryCode": "PT",
"airportCode": "LIS"
},
"flightSegments": [
{
"carrier": "TP",
"flightNumber": "204",
"originIata": "JFK",
"destinationIata": "LIS",
"departsAtLocal": "2026-12-10T19:05:00",
"arrivesAtLocal": "2026-12-11T07:00:00",
"isReturn": false
},
{
"carrier": "TP",
"flightNumber": "209",
"originIata": "LIS",
"destinationIata": "JFK",
"departsAtLocal": "2026-12-17T11:30:00",
"arrivesAtLocal": "2026-12-17T14:45:00",
"isReturn": true
}
]
}| Field | Format | Required | Purpose |
|---|---|---|---|
| v | Integer, 1 | Yes | Schema version, so later changes don't break live links. |
| partnerReferralId | OTA- + 10 characters | Yes | Your OTA Partner Referral ID. Voyani resolves the partner from it. |
| bookingReference | Text | Yes | Your confirmation reference. With partnerReferralId it is the dedupe key, and the app shows it on the booking. |
| bookingType | flight or hotel | Yes | Which booking this link carries, and so which of flightSegments or hotel Voyani reads. |
| referredAt | ISO-8601 with offset, e.g. Z | Yes | When the traveler tapped the button. Voyani keeps it as the record of their consent. |
| totalAmount, currency | Decimal; ISO 4217 code | Optional | What the traveler paid you. Without currency Voyani uses your partner payment currency, and a missing amount is shown as incomplete. |
| destination.city, countryCode, airportCode | Text; country code; IATA code | Recommended | The trip destination. The city is the only booking detail shown before the traveler signs in. |
| traveler.firstName, lastName, email, phone | Text | Optional | Only as your consent and integration allow. The email lets Voyani prepare the traveler's account before they sign in. |
| support.displayName, phone, email, url | Text | Optional | Your traveler support for this booking. Your OTA Partner Profile's support details take priority. |
| flightSegments[] | Array | Recommended, 1 or more | Each segment becomes part of the trip, its Timeline and its Wallet item. |
| flightSegments[].carrier | IATA, 2 characters | Recommended | The airline that sold the flight. |
| flightSegments[].flightNumber | Text | Recommended | Flight number. With the carrier it titles the booking, for example TP 204 JFK-LIS. |
| flightSegments[].originIata, destinationIata | IATA airport code | Optional | Where the segment departs and lands. |
| flightSegments[].departsAtLocal, arrivesAtLocal | Local ISO-8601, no offset | Recommended | Local time at each airport, as you sold it. Voyani does not convert it. |
| flightSegments[].isReturn | true or false | Optional | true for a leg of the return journey. Defaults to false. |
| flightSegments[].operatingCarrier | IATA, 2 characters | Optional | The airline operating a codeshare sold under carrier. |
| flightSegments[].seat, cabinClass | Text | Optional | Shown on the Timeline entry. |
- Recommended fields never block the link. When the outbound segment lacks one, the booking is created and shown as incomplete.
- One-way trips are valid: send only the outbound segments.
Hotel payload
Draft specOne hotel stay, with bookingType set to hotel.
{
"v": 1,
"partnerReferralId": "OTA-7K3QZ9M2XA",
"bookingReference": "HX88213",
"bookingType": "hotel",
"referredAt": "2026-11-06T09:00:00Z",
"destination": {
"city": "Lisbon",
"countryCode": "PT"
},
"hotel": {
"name": "Example Lisbon Hotel",
"checkInLocal": "2026-12-11T15:00:00",
"checkOutLocal": "2026-12-17T11:00:00"
}
}{
"v": 1,
"partnerReferralId": "OTA-7K3QZ9M2XA",
"bookingReference": "HX88213",
"bookingType": "hotel",
"referredAt": "2026-11-06T09:00:00Z",
"destination": {
"city": "Lisbon",
"countryCode": "PT"
},
"hotel": {
"name": "Example Lisbon Hotel",
"checkInLocal": "2026-12-11T15:00:00",
"checkOutLocal": "2026-12-17T11:00:00",
"address": "10 Example Street, Lisbon",
"roomDescription": "Double room, city view"
},
"totalAmount": 1240.5,
"currency": "EUR",
"traveler": {
"firstName": "Ana",
"lastName": "Silva",
"email": "ana.silva@example.com",
"phone": "+351910000000"
},
"support": {
"displayName": "Example Travel support",
"phone": "+18005550100",
"email": "help@example-travel.com",
"url": "https://example-travel.com/help"
}
}| Field | Format | Required | Purpose |
|---|---|---|---|
| v | Integer, 1 | Yes | Schema version, so later changes don't break live links. |
| partnerReferralId | OTA- + 10 characters | Yes | Your OTA Partner Referral ID. Voyani resolves the partner from it. |
| bookingReference | Text | Yes | Your confirmation reference. With partnerReferralId it is the dedupe key, and the app shows it on the booking. |
| bookingType | flight or hotel | Yes | Which booking this link carries, and so which of flightSegments or hotel Voyani reads. |
| referredAt | ISO-8601 with offset, e.g. Z | Yes | When the traveler tapped the button. Voyani keeps it as the record of their consent. |
| totalAmount, currency | Decimal; ISO 4217 code | Optional | What the traveler paid you. Without currency Voyani uses your partner payment currency, and a missing amount is shown as incomplete. |
| destination.city, countryCode, airportCode | Text; country code; IATA code | Recommended | The trip destination. The city is the only booking detail shown before the traveler signs in. |
| traveler.firstName, lastName, email, phone | Text | Optional | Only as your consent and integration allow. The email lets Voyani prepare the traveler's account before they sign in. |
| support.displayName, phone, email, url | Text | Optional | Your traveler support for this booking. Your OTA Partner Profile's support details take priority. |
| hotel | Object, one per link | Recommended | The stay. It becomes a Timeline entry and a Wallet item. |
| hotel.name | Text | Recommended | Property name. It titles the booking on the Timeline and in the Wallet. |
| hotel.checkInLocal, checkOutLocal | Local ISO-8601, no offset | Recommended | Start and end of the stay, in the hotel's local time. The last check-out ends the trip. |
| hotel.address | Text | Optional | A precise location for the map. |
| hotel.roomDescription | Text | Optional | Room type, shown on the booking. |
- Recommended fields never block the link. A missing name or date creates the booking and shows it as incomplete. Voyani fills nothing in.
- One link carries one hotel. Send a separate link for each stay.
Not in the link
The payload has no field for these. Don't add them.
| Item | Where Voyani gets it |
|---|---|
| Rate plan, loyalty numbers, payment details | Not carried. The payload has no field for them. |
| Special requests and free-text notes | Not carried. Free text can contain personal details. |
| Partner UUID | Resolved by Voyani from partnerReferralId. |
| Consent flag | Voyani records the tap from referredAt. |
How Voyani handles the link
- Known fields only. Fields outside this specification are ignored.
- One booking per reference. partnerReferralId plus bookingReference is the dedupe key. Reopening the link, or opening it on another device, never creates a second account, trip or booking.
- Missing or malformed data. Without one of the five required fields the link is refused. Anything else missing still creates the records it can, shown as incomplete. Voyani never invents a value.
- Before login. The traveler sees the destination city only. Booking details appear after they sign in and the booking is bound to their account.
- Binding. The first verified account binds the booking. A different account cannot claim it afterward.
Before you go live
- HTTPS only. It is a universal link, so the app, mobile web and desktop all keep your referral.
- Keep t at 1,500 characters or fewer. Longer values are refused.
- The link stays valid until 10 days after the trip ends, meaning the last flight arrival or the hotel check-out, unless Voyani revokes it.
- Build t as the Base64url-encoded JSON note, one booking per link.