# Travel4Site × Travelpayouts

**Primary network: [Travelpayouts](https://www.travelpayouts.com/).**
Booking.com, Expedia, and other OTAs are programs *on that platform*. We do not run a direct Booking.com AID.

The site-wide head script is already installed (`inc/header.php`):

```
https://emrld.ltd/NTczMjY4.js?t=573268
```

That snippet is the **Drive / Emerald / LinkSwitcher** loader (same family; MoneyScript is deprecated in favor of Drive). After it is on the site, features are toggled in the Travelpayouts dashboard, not in our PHP.

We do **not** claim “best price guaranteed.”

---

## Drive (AI) — what it is, what to turn on

Docs: [What is Drive](https://support.travelpayouts.com/hc/en-us/articles/21844777943058-What-is-Travelpayouts-Drive), [Drive settings](https://support.travelpayouts.com/hc/en-us/articles/32083238510482-Drive-functionalities-and-settings), [FAQ](https://support.travelpayouts.com/hc/en-us/articles/32097258847378-FAQ-about-Drive), [install](https://support.travelpayouts.com/hc/en-us/articles/21844864838290-How-to-install-Drive-on-your-website).

Drive reads page copy and visitor behavior, then injects affiliate tools. English-language sites are in scope (keyword linking and in-article recommendations are English-only).

| Feature | What it does | Use on Travel4Site? |
| --- | --- | --- |
| **Link switching** | Rewrites existing Booking.com / Expedia / other brand URLs into Travelpayouts tracked links | **On.** This is why the stay form can keep posting to `booking.com/searchresults.html`. |
| **Keyword linking** | Turns travel words in the article into affiliate links | **On for guides only.** Exclude legal/tax URLs in Drive settings. |
| **Recommendations in articles** | Inserts hotel / tour / car blocks that match the page | **On for destination + trip-type pages.** Same exclusions. |
| **Smart previews** | Hover/tap preview on travel links. Per-link opt-out: `data-tooltip-ignore="true"` | **Desktop only** if it feels noisy; off on mobile if layout shifts. |
| **Targeted offers** | Opens a relevant offer in a **background tab** when it thinks the visitor will book | **Off.** Hostile UX, fights WCAG 2.2 change-of-context, and this site’s “we do not autoplay / do not ambush” voice. |

### Operator clicks after this deploy

1. Travelpayouts → the travel4site.com **Project** → **Unlock Drive** (Drive is website-only).
2. Enable: link switching, keyword linking, recommendations.
3. Disable: targeted offers.
4. **Exclude pages** (full URLs):

   - `https://travel4site.com/crypto-territories/`
   - `https://travel4site.com/territories/`
   - `https://travel4site.com/privacy/`
   - `https://travel4site.com/terms/`
   - `https://travel4site.com/disclaimer/`
   - `https://travel4site.com/affiliates/`
   - `https://travel4site.com/about/`

   Smart previews and targeted offers **cannot** be page-excluded in the UI; if they leak onto legal pages, ask Travelpayouts support to exclude them. Stats: **Reports → Content analytics**.

---

## API catalog — what we can use vs skip

Source: [API and data](https://support.travelpayouts.com/hc/en-us/categories/200358578-API-and-data), [brands with APIs](https://support.travelpayouts.com/hc/en-us/articles/20384016664594-Brands-that-provide-access-to-APIs-and-data-feeds-for-Travelpayouts-partners).

Token lives **off the docroot** (same pattern as Weather4Site’s NWS config):

- source: `~/.travel-api-key` (mode 600)
- PHP: `~/.travel4site/tp-config.php` (mode 600), loaded by `inc/affiliate.php`

**Never** put the token in `public_html` or in a browser request. Same pattern as the NWS proxy: server cache, one User-Agent, no invented prices.

### Use later (needs token; good fit)

| API | Why it fits | Notes |
| --- | --- | --- |
| **Aviasales Data API** (`/aviasales/v3/prices_for_dates`, `get_popular_directions`, `/v1/city-directions`) | Cached “people searched this recently” fares for NYC→SJU, MIA→EYW, etc. Honest as *indicative*, not a live quote | No extra brand approval. Rate limits ~60–600 req/min by method. Cache 6–24h off-docroot. Disclose “Aviasales search cache, not a ticket.” |
| **Aviasales GraphQL** | Same data, fewer round-trips | Token in `X-Access-Token`. |
| **Partner links API** `POST /links/v1/create` | Server-side convert of Booking.com URLs if Drive is off on a page | 100 req/min, 10 URLs/request. Not for Kiwi/Expedia UK. |
| **IATA / cities / autocomplete JSON** | Power a U.S. airport picker on `/hotels/` without scraping | Public dumps + suggest endpoint. |
| **Statistics `execute_query`** | Optional internal earnings pull | 30 req/min. Dashboard is enough unless we build an ops page. |

### Do not implement (wrong product or dead)

| API | Why not |
| --- | --- |
| **Aviasales Flight Search API** (live itineraries, md5 signature, `x-user-ip`) | Needs **50k MAU**, 9% search→Book and 5% Book→purchase, server-only, hide `/search/` from robots, no mixing other metas. We are an editorial site, not a fare engine. Use White Label widget or Drive instead. |
| **Hotellook API / old hotel widgets** | **Shut off 20 Oct 2025.** No replacement hotel API in the catalog yet. Keep Booking.com search + Drive. |
| **Kiwi Tequila API** | 50k MAU gate. |
| **White Label App / iOS/Android SDK** | Mobile-app product. Hotels tab already dropped in WL App 1.5. |
| **GetTransfer, Tiqets, Viator feeds, Airalo, Omio, Level.travel, Yandex, Sutochno** | Either RU-centric, approval-gated, or not this site’s U.S. trip IA. Revisit Viator/GetYourGuide **widgets** (not raw feeds) if we add a tours block. |
| **Deprecated stats/link APIs** | Use `statistics/v1` and `links/v1` only. |

### White Label Web (not a REST API, still useful)

[What is White Label](https://support.travelpayouts.com/hc/en-us/articles/203955753-What-is-White-Label-Web-by-Travelpayouts-): branded **flight** search page or embeddable **widget**. New WL (from 2025) has **no built-in hotel search** (Hotellook gone); hotels are extra catalog widgets. Booking.com fares are **not** in WL (Booking.com policy).

**Live:** White Label flight search is on `/flights/` only. `/hotels/` is hotels (Booking.com form). Needs CNAME or embed code from the dashboard, plus CSP for the WL host.

---

## White Label Web (flights) — live on /flights/

Docs: [What is White Label Web](https://support.travelpayouts.com/hc/en-us/articles/203955753-What-is-White-Label-Web-by-Travelpayouts-), [Widget type setup](https://support.travelpayouts.com/hc/en-us/articles/26857907357458-Setting-up-a-White-Label-with-Widget-type).

We use the **Widget** type (no DNS CNAME). The Page type would need `flights.travel4site.com → whitelabel.travelpayouts.com` and is optional later.

The new White Label (2025) is **flights only**. Hotels stay on the Booking.com form on `/hotels/`. Booking.com fares are not in White Label (their policy). Hotellook is gone.

In the WL dashboard, turn **Show hotels** **off**. That checkbox does not search hotels on this site; when left on it only confuses visitors. We also set `showHotels: false` in `TPWL_CONFIGURATION` so the box stays hidden even if the dashboard flag is still on.

### Operator: create the widget (once)

1. Travelpayouts → **White Label → WL Web → Create new → Widget**.
2. Project: travel4site.com. Language: English. Currency: USD.
3. Colors: teal `#0b5555`, terracotta `#c45c2a` if the picker allows — match Travel4Site, don’t pick default orange.
4. On **Your widget code**, copy `wl_id` from:

   `https://tpwgts.com/wl_web/main.js?wl_id=NUMBER`

5. Widget **22029** is live in `inc/affiliate.php`:

   ```php
   const TR_TP_WL_ID = '22029';
   ```

6. Rebuild:

   ```bash
   python3 /home/the4site/public_html/travel4site.com/assets/build_site.py
   ```

Until `TR_TP_WL_ID` is set, `/flights/` shows a setup note instead of an empty box. After it is set, head loads `tpwgts.com` only on `/flights/`. Search results stay on `/flights/` (`resultsURL`).

Mount points (official): `#tpwl-search` (form), `#tpwl-tickets` (results).

## CT casino fly-in widgets (Aviasales search form)

Not White Label. Two `tpwgts.com/content` search forms per CT page (`promo_id=7879`). Destination slug locked (BDL / PVD); origin from geo; `show_hotels=false`; `powered_by=false`. Search opens Aviasales.

- Marker: `776861` (`TR_TP_MARKER`)
- Project / `trs`: `573268` (same Drive snippet)
- Widget: Aviasales search form `promo_id=7879`, `campaign_id=100`
- Host: `www.aviasales.com/search`
- SubIDs:
  - `t4s-ct-hub-bdl` / `t4s-ct-hub-pvd` on `/destinations/connecticut-casinos/`
  - `t4s-mohegan-bdl` / `t4s-mohegan-pvd` on `/destinations/mohegan-sun/` (BDL first)
  - `t4s-foxwoods-bdl` / `t4s-foxwoods-pvd` on `/destinations/foxwoods/` (PVD first)
  - `t4s-crypto-sju` / `t4s-crypto-stt` on `/crypto-territories/` (SJU first)
  - `t4s-residency-sju` / `t4s-residency-stt` on `/practical-advice/crypto-residency/`
  - `t4s-pr-sju` / `t4s-pr-stt` on `/destinations/puerto-rico/`
  - `t4s-usvi-stt` / `t4s-usvi-sju` on `/destinations/us-virgin-islands/` (STT first)
- Each form lives in a same-origin iframe (`/assets/tp-search.php`) so Cascoon JSONP/chunks are not killed by the site CSP. Parent `frame-src` includes `'self'`; the iframe document has a looser CSP and `X-Frame-Options: SAMEORIGIN`.
- Official airport URLs: [bradleyairport.com](https://bradleyairport.com/), [flyri.com](https://flyri.com/) (pvdairport.com 301s here). This host may see Cloudflare 403; still the official sites.

Do not add a second affiliate network on these blocks. Do not put these widgets on weather4site or `/crypto-territories/`.

## Config

`inc/affiliate.php`

```php
const TR_TRAVELPAYOUTS = true;
const TR_TP_MARKER = '';      // partner ID, lower-left of dashboard
const TR_BOOKING_AID = '';    // leave empty — Drive/LinkSwitcher owns Booking.com
// TR_TP_API_TOKEN is defined in ~/.travel4site/tp-config.php
```

Rebuild after changing header or builder:

```bash
python3 /home/the4site/public_html/travel4site.com/assets/build_site.py
```

## Disclosure copy

“We may earn a commission if you book through these links, at no extra cost to you.”
