<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Matan Rabi</title>
    <description>The latest articles on DEV Community by Matan Rabi (@matanrabi).</description>
    <link>https://dev.to/matanrabi</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4106861%2F9ed924bf-73b8-4d8d-82dd-07204e1e196d.jpg</url>
      <title>DEV Community: Matan Rabi</title>
      <link>https://dev.to/matanrabi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/matanrabi"/>
    <language>en</language>
    <item>
      <title>I benchmarked seven hotel price APIs on the same Rome room, and the prices were 16% apart because of tax</title>
      <dc:creator>Matan Rabi</dc:creator>
      <pubDate>Wed, 07 Oct 2026 14:52:15 +0000</pubDate>
      <link>https://dev.to/matanrabi/i-benchmarked-seven-hotel-price-apis-on-the-same-rome-room-and-the-prices-were-16-apart-because-3480</link>
      <guid>https://dev.to/matanrabi/i-benchmarked-seven-hotel-price-apis-on-the-same-rome-room-and-the-prices-were-16-apart-because-3480</guid>
      <description>&lt;p&gt;I run FlightPowers, a small API that reads live Booking.com rates, so I'm biased about one row of this table. I wanted to know how it holds up next to the APIs people usually compare it with, so I spent an afternoon sending them all the same questions and kept every response.&lt;/p&gt;

&lt;h2&gt;
  
  
  The setup
&lt;/h2&gt;

&lt;p&gt;Same stay for everyone: check-in 2026-11-20, check-out 2026-11-23, 2 adults, 1 room, USD. Three questions, three runs each, median wall time from one server in the US:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A destination search for Lisbon, sorted by price where the API can sort.&lt;/li&gt;
&lt;li&gt;One named hotel: Hotel Artemide in Rome. (I started with Hotel Sant'Angelo, but it was sold out on Booking.com for those dates.)&lt;/li&gt;
&lt;li&gt;That same hotel seen from Germany and from the US, where the API has an input for it.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Free tiers only. SerpApi got &lt;code&gt;no_cache=true&lt;/code&gt;, because its default hands back an identical search from cache for an hour and that would have flattered its time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Speed and sorting
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;API (source)&lt;/th&gt;
&lt;th&gt;Lisbon search, median&lt;/th&gt;
&lt;th&gt;sorts by price&lt;/th&gt;
&lt;th&gt;one named hotel&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;StayAPI (Booking.com)&lt;/td&gt;
&lt;td&gt;1.1 s&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;2 calls: ID lookup, then prices (2.5 s for the prices call)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SearchApi (Booking.com)&lt;/td&gt;
&lt;td&gt;1.9 s&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;room list in 2 calls: search for the URL, then the property (3.0 s for that call)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HasData (Booking.com)&lt;/td&gt;
&lt;td&gt;2.1 s&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;room list in 2 calls: search for the URL, then the place (3.2 s for that call)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SerpApi (Google Hotels)&lt;/td&gt;
&lt;td&gt;2.4 s&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;1 call by name (2.5 s)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FlightPowers, mine (Booking.com)&lt;/td&gt;
&lt;td&gt;7.9 s&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;1 call by name (10.2 s)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Apify voyager/booking-scraper&lt;/td&gt;
&lt;td&gt;75 s with actor start&lt;/td&gt;
&lt;td&gt;asked, rows came back unsorted&lt;/td&gt;
&lt;td&gt;1 run by name (39 s, one run)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Xotelo (TripAdvisor rates)&lt;/td&gt;
&lt;td&gt;0.7 s, but the list takes no dates&lt;/td&gt;
&lt;td&gt;n/a&lt;/td&gt;
&lt;td&gt;by TripAdvisor key (0.7 s)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Mine is the slow one. It loads the page in a real browser through a residential proxy for every call, and you pay for that in seconds. It also has no price sort yet: I sent &lt;code&gt;"sort": "price"&lt;/code&gt; and it was accepted and ignored, which is a bug on my list.&lt;/p&gt;

&lt;p&gt;SearchApi's and HasData's search take a hotel name too (SearchApi put Hotel Sant'Angelo first when I searched it by name), so one row price for a named hotel is a single call there as well. Their second call is for the full room list.&lt;/p&gt;

&lt;h2&gt;
  
  
  One room, two prices
&lt;/h2&gt;

&lt;p&gt;Hotel Artemide, Basic Double, those three nights. Here is what each API called the price:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;where the number came from&lt;/th&gt;
&lt;th&gt;what came back&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HasData&lt;/td&gt;
&lt;td&gt;$914.64 + $142.12 tax = $1,056.76&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;StayAPI, US market&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;total_price&lt;/code&gt; $914.64, tax listed as not included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;StayAPI, German market&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;total_price&lt;/code&gt; $1,061.71, tax listed as included&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SearchApi&lt;/td&gt;
&lt;td&gt;$915, no tax field on the room rows&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;FlightPowers, &lt;code&gt;proxy_country=us&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;$1,057, three runs out of three&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Same rate underneath. Booking.com shows a US visitor the room before tax and adds 10% VAT and the Rome city tax at the end. The German view folds them into the price. So the number you store depends on which field an API calls the price and which market it read from. StayAPI's &lt;code&gt;total_price&lt;/code&gt; means before tax in one market and after tax in the other, for the same room. Its docs warn that the market changes tax display, and the tax breakdown says which way it went, so you can fix it if you read it.&lt;/p&gt;

&lt;p&gt;If you load hotel rates into anything that compares sources or countries, normalise to the tax-inclusive total first. Otherwise a 16% "price gap" shows up that's only accounting.&lt;/p&gt;

&lt;p&gt;Two smaller ones. The cheapest Lisbon row on SearchApi and on HasData was the same hostel bunk ($51 before tax, $81 after). And the Apify scraper's cheapest result was one bed in a 10-bed dorm priced for one person, on a search for two adults.&lt;/p&gt;

&lt;h2&gt;
  
  
  Does the country change the rate?
&lt;/h2&gt;

&lt;p&gt;A little, on this hotel. StayAPI's before-tax figure was $919.14 from Germany and $914.64 from the US. Mine, tax included both times, read $1,028 from Germany on two of three runs and $1,057 from the US on all three. Without a pinned country mine moves more ($935, $1,011 and $1,062 for the Basic Double on three calls to the room list), because each call can leave from a different country's residential IP. Pinning helps but doesn't settle it: the Germany runs still read $1,062 once and $1,028 twice.&lt;/p&gt;

&lt;h2&gt;
  
  
  What it costs at the entry plan
&lt;/h2&gt;

&lt;p&gt;Read from each vendor's pricing page the same afternoon:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HasData: a Booking.com call is 10 credits, so about $0.003 a call on the $59 plan (200,000 credits)&lt;/li&gt;
&lt;li&gt;SearchApi: $0.004 ($40 for 10,000), 100 free requests once&lt;/li&gt;
&lt;li&gt;FlightPowers: $0.005 ($10 for 2,000), 10 free a month&lt;/li&gt;
&lt;li&gt;SerpApi: $0.025, their cheapest plan is $25 for 1,000, 250 free a month&lt;/li&gt;
&lt;li&gt;StayAPI: $0.033 ($49 for 1,500), 50 free requests once&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So two of them are cheaper per call than mine. What mine has is the $10 entry and one tax-inclusive total from a country you pick.&lt;/p&gt;

&lt;h2&gt;
  
  
  Caveats
&lt;/h2&gt;

&lt;p&gt;One afternoon, one server, three runs a query. Google Hotels is a metasearch across sellers (34 of them for Artemide), so SerpApi's Lisbon list isn't the same set of hotels as the Booking.com APIs. Makcorps isn't in the timings because its sign-up wanted a username and password and I stuck to Google sign-ins, and the Booking.com Demand API needs a partner contract.&lt;/p&gt;

&lt;p&gt;The full write-up, with every price source and the per-call timings, is on &lt;a href="https://flightpowers.com/guides/hotel-rates-api-benchmark-2026" rel="noopener noreferrer"&gt;the benchmark page&lt;/a&gt;. I'll rerun it next month. If you store hotel prices somewhere, I'm curious whether you keep the before-tax number with tax in its own column, or the total.&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>benchmark</category>
      <category>travel</category>
    </item>
    <item>
      <title>I benchmarked four Google Flights APIs on the same searches, and the fares matched to the dollar</title>
      <dc:creator>Matan Rabi</dc:creator>
      <pubDate>Wed, 07 Oct 2026 14:50:55 +0000</pubDate>
      <link>https://dev.to/matanrabi/i-benchmarked-four-google-flights-apis-on-the-same-searches-and-the-fares-matched-to-the-dollar-30pb</link>
      <guid>https://dev.to/matanrabi/i-benchmarked-four-google-flights-apis-on-the-same-searches-and-the-fares-matched-to-the-dollar-30pb</guid>
      <description>&lt;p&gt;I sell a Google Flights API (FlightPowers), and I wanted a real answer to how it compares to SerpApi, SearchApi and HasData. So I ran the same three searches through all four in the same hour on 7 October 2026 and timed every call.&lt;/p&gt;

&lt;p&gt;Disclosure up front: I built one of the four rows. The method, the places where mine loses and the timing of every single call are public on the &lt;a href="https://flightpowers.com/guides/flight-api-benchmark-2026" rel="noopener noreferrer"&gt;benchmark page&lt;/a&gt;, and I'll re-run it every month.&lt;/p&gt;

&lt;h2&gt;
  
  
  The searches
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;A round trip, JFK to LHR, out 18 November, back 25 November.&lt;/li&gt;
&lt;li&gt;A one way, TLV to BKK on 3 December.&lt;/li&gt;
&lt;li&gt;A flexible scan, LHR to BCN, any departure from 10 to 16 November, 3 nights (seven date pairs).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;One adult, economy, USD, three runs per search per API, from a VM in GCP us-central1. The time quoted is the median of the three runs, from sending the request to reading the last byte.&lt;/p&gt;

&lt;h2&gt;
  
  
  The results
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;FlightPowers (mine)&lt;/th&gt;
&lt;th&gt;SerpApi&lt;/th&gt;
&lt;th&gt;SearchApi&lt;/th&gt;
&lt;th&gt;HasData&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cheapest fare, all three searches&lt;/td&gt;
&lt;td&gt;same&lt;/td&gt;
&lt;td&gt;same&lt;/td&gt;
&lt;td&gt;same&lt;/td&gt;
&lt;td&gt;same&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Round trip, both legs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.27 s, 1 request&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;6.36 s, 2 requests&lt;/td&gt;
&lt;td&gt;4.29 s, 2 requests&lt;/td&gt;
&lt;td&gt;7.56 s, 2 requests&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;First round-trip price&lt;/td&gt;
&lt;td&gt;3.27 s&lt;/td&gt;
&lt;td&gt;2.26 s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.98 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;5.23 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;One way&lt;/td&gt;
&lt;td&gt;1.56 s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;1.34 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1.50 s&lt;/td&gt;
&lt;td&gt;2.79 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;7-date scan, 7 calls in parallel&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;3.11 s&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;4.54 s&lt;/td&gt;
&lt;td&gt;28.37 s*&lt;/td&gt;
&lt;td&gt;15.99 s*&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Whole range in one call&lt;/td&gt;
&lt;td&gt;MCP server, bills 7&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;calendar engine, bills 1&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Price history series&lt;/td&gt;
&lt;td&gt;no&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;td&gt;yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Free tier&lt;/td&gt;
&lt;td&gt;10 a month&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;250 a month&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;100, once&lt;/td&gt;
&lt;td&gt;67 a month&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Entry plan&lt;/td&gt;
&lt;td&gt;$10 for 2,500&lt;/td&gt;
&lt;td&gt;$25 for 1,000&lt;/td&gt;
&lt;td&gt;$40 for 10,000&lt;/td&gt;
&lt;td&gt;$59 for 13,333&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Per 1,000 round trips with both legs&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$4.00&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$50.00&lt;/td&gt;
&lt;td&gt;$8.00&lt;/td&gt;
&lt;td&gt;$8.85&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;* One call took 16 to 28 seconds in two of the three runs (the median call was 1.9 s on SearchApi and 3.0 s on HasData, which ran 5 at a time on its trial account). A parallel scan waits for its slowest call.&lt;/p&gt;

&lt;h2&gt;
  
  
  The fares were identical
&lt;/h2&gt;

&lt;p&gt;All four returned $692 for the round trip, $619 for the one way and the same lowest price on each of the seven scan dates ($93 at the bottom, leaving Saturday 14 November), with the same Google price range. The only difference was a label: SearchApi called two of the seven scan dates "high" where the other three said "typical". That makes sense, since all four read the same Google Flights results, but it means nobody should pick one of these on "better prices".&lt;/p&gt;

&lt;h2&gt;
  
  
  The round trip is where they differ
&lt;/h2&gt;

&lt;p&gt;SerpApi, SearchApi and HasData answer a round trip with the outbound options, each priced as a round-trip total. The return flight is a second request with a &lt;code&gt;departure_token&lt;/code&gt;, and all three say so in their docs (quoted on the page). Mine pairs both legs in one request, which is why "both legs" is one request and 3.27 s here, and why a round trip with its return flight works out at $4.00 per 1,000 against $8.00 to $50.00.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-X&lt;/span&gt; POST https://api.flightpowers.com/v1/flights/roundtrip &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"x-api-key: &lt;/span&gt;&lt;span class="nv"&gt;$FLIGHTPOWERS_API_KEY&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Content-Type: application/json"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="s1"&gt;'{"from_airport":"JFK","to_airport":"LHR","departure_date":"2026-11-18","return_date":"2026-11-25","currency":"USD"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Where mine loses
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;The first price.&lt;/strong&gt; SearchApi and SerpApi put a round-trip total on the table faster (1.98 s and 2.26 s against my 3.27 s). If you never need the return flight's details, they're quicker.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Every itinerary.&lt;/strong&gt; With &lt;code&gt;limit: 100&lt;/code&gt; my round trip took 15.68 s, since each extra outbound needs its own return-leg page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;The free tier.&lt;/strong&gt; Ten requests a month on the key. The bigger free path is the ad-supported MCP server (50 searches a day with a Google sign-in), which only helps if you use an MCP client.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Price history.&lt;/strong&gt; The other three return a &lt;code&gt;price_history&lt;/code&gt; series, and I return Google's band and its low, typical or high verdict only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Date grids.&lt;/strong&gt; SearchApi's calendar engine prices every date pair for one billed search. My one-call scan bills one request per date pair.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Billing.&lt;/strong&gt; The other three count successful searches only. On RapidAPI every request that reaches my listing counts, one I reject as invalid included.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  APIs I couldn't run
&lt;/h2&gt;

&lt;p&gt;FlightAPI.io and Duffel only offer password sign-ups (I only used Google sign-ins for this), Duffel is a booking API with test data anyway, Amadeus Self-Service closed in July 2026, and Kiwi Tequila, Skyscanner and Travelpayouts need an application, an invitation or a traffic minimum. Sources for each are on the &lt;a href="https://flightpowers.com/guides/flight-api-benchmark-2026" rel="noopener noreferrer"&gt;benchmark page&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you've used any of these in production, I'd like to know which number actually made you pick one. The full table, the method and the per-call JSON are on the page :)&lt;/p&gt;

</description>
      <category>api</category>
      <category>webdev</category>
      <category>benchmark</category>
      <category>travel</category>
    </item>
  </channel>
</rss>
