One quote is four requests on one address.
Rotate the exit mid-chain and the poll comes back empty, the point of sale flips, or the currency changes and the row still parses.
- EX06:20 — 07:451h 25m · Direct · EX 1412
- EX09:55 — 11:201h 25m · Direct · EX 1418
- EX13:10 — 14:351h 25m · Direct · EX 1424
- EX17:40 — 19:051h 25m · Direct · EX 1430
- EX21:15 — 22:401h 25m · Direct · EX 1436
The response was a 200 either way. A stale fare and a missing one look the same in your log.
- EX06:20 — 07:451h 25m · Direct · EX 1412
- EX09:55 — 11:201h 25m · Direct · EX 1418
- EX13:10 — 14:351h 25m · Direct · EX 1424
- EX17:40 — 19:051h 25m · Direct · EX 1430
- EX21:15 — 22:401h 25m · Direct · EX 1436
One session held the POS and the currency across the whole chain, so every row priced.
Sample fare board, illustrative. The interruption wording is the real one, and it arrives as a 200.
The fare parsed. The point of sale had flipped.
Carrier and OTA front ends behind commercial bot management do not always answer with a 403. You can get a document with the price nodes stripped, a stale cached fare, or a fabricated sold-out, so your error rate stays flat while the dataset rots. The fan-out of origin, date, pax, cabin and POS multiplies every blocked attempt, and you pay twice — once for the block, once for the retry.
Rotation breaks the chain→Sticky is an account mode, not a flag
Most pools rotate per request. One quote is a search, a poll on the search id, the priced itinerary, then ancillaries: four calls the target expects from one address.
Ask the operator to put your account in sticky mode: every connection from one machine then leaves through the same exit for the window, 600 seconds by default and raised on request.
You draw the exit blind→Reputation scored per target
Fare hosts differ: a carrier storefront, an OTA and a metasearch front end each police traffic on their own terms. A pool hands you an address with no record of how the host you are pricing has received it.
The question is whether this exit is landing against this host right now — a host that has just repriced, or just tightened, or is mid-sale. Each one holds its own view of each exit.
A soft 200 looks like a win→Re-runs absorbed, not billed
No 403, no CAPTCHA. Price nodes removed, sold-out forced, a cached fare from hours ago. On a pool that meters every response, that lands as a success and the bytes are billed. No edge sees it, ours included — so the assertion has to sit in your code before you store the row.
An attempt that fails at the transport — reset, TLS error, block status, a known challenge response — is re-run through another exit before your poll loop sees it, and absorbed rather than billed.
No column says which exit priced it→Every row carries its egress country
Nothing on the row records the country you asked for or the point of sale you were actually served. When two runs disagree, you cannot tell whether the market moved or the routing did.
Country rides on the username as USER-country-de, at one per-GB rate with no geo surcharge. Store what you asked for next to the point of sale and currency you were served.
Before you point a crawler at it.
How do I keep one exit across the four calls of a quote?
Sticky mode is set on your account by the operator; it is not passed per request, because the username carries no session id — only the country and an optional -rotate, which you leave off for a quote chain. The key is your source IP: every connection from one machine leaves through the same exit until it has been idle for 600 seconds, the default, longer on request. One machine drives one pinned chain at a time, so several markets at once means several source machines.
How do I tell a real 200 from a soft block that parses cleanly?
You assert on content, and you pay for the bytes either way. The edge acts on what it can see — connection failures, TLS errors, block status codes, known challenge responses — and re-runs those. A stripped fare page served as a clean 200 is not visible to it. Keep your own check in front of the sink: price element present, returned currency matching the point of sale you asked for. Reissue when it fires.
Does country targeting mean the airline agrees I am in that country?
Only the target's own geo vendor gets a vote, so treat its response as ground truth: which storefront it redirected you to, which currency it returned, the country header it echoed. If the storefront is wrong, request again in the same country with -rotate on the username (USER-country-de-rotate): each new connection then takes the next exit in that country, never the one before it. Recording requested country against returned point of sale on every row turns this from a mystery into a filterable column.
Headless browsers will eat my bandwidth budget.
Then buy concurrency, not volume. Rendering an OTA results page is far heavier than the JSON behind it; unlimited bandwidth is priced on concurrent connections, not bytes. If you can reach the public JSON directly, metered is usually cheaper: a flat rate per gigabyte, and traffic never expires. Current plans are on the pricing page.
Will collecting fares like this earn me an abuse report?
Public fare and rate pages, collected at a rate the target tolerates, for legitimate commercial use. The acceptable use policy enforces it: no aggressive scraping that generates abuse reports, no authenticated flows, no CAPTCHA solving, no login or paywall circumvention. Some carriers litigate against scrapers, so read each target's terms and rate-limit yourself before you scale.
One credential, every job.
All six →Run one market, then every market you price
1 GB free to start. Point your fare crawler at the endpoint on your dashboard with -country-de, then compare the point of sale and currency you were served against the one you asked for.
Get 1 GB free