🎉 Developer Free Trial — 1 week of full API access, no credit card required. Claim your trial →
API Reference

API Overview

ScrapeGuys exposes real-time travel pricing through a small set of REST endpoints. This page covers the concepts shared by every scraper — authentication, base URLs, the async job workflow, rate limits and errors. Each scraper then has its own reference page.

Base URLs

The scrapers are served by two independent API surfaces. Each has its own API keys (see Authentication).

SurfaceBase URLCovers
Hotel APIhttps://gumo.co.in/api/v1/scraperMeta (Google Hotels) + OTA (Agoda, Booking.com, MakeMyTrip, Expedia, Goibibo)
Flight APIhttps://gumo.co.in/api/v1/flight-scraperMeta (Google Flights) + OTA (MakeMyTrip)
Note: replace gumo.co.in with the host provided to you during onboarding if it differs. All examples on these docs use the host above.

Authentication

Every request must include your API key in the X-API-Key header. Keys are 68-character strings; the Hotel API issues gsk_… keys and the Flight API issues fsk_… keys. The two are independent — a Hotel key does not authenticate the Flight API and vice-versa.

Scopes. Both key types carry an explicit scope list controlling which sources they may call. A gsk_… key can hold: gmaps (Google Hotels), ota:agoda (Agoda), ota:booking (Booking.com), ota:makemytrip (MakeMyTrip), ota:expedia (Expedia), ota:goibibo (Goibibo), and destination:booking (Destination Search). A fsk_… key can hold: google_flights (Google Flights) and/or makemytrip (MakeMyTrip Flights, both its app and desktop platforms), per source. Which of these a given key actually carries depends on when it was issued and what was requested for it — see below. Calling an endpoint or source outside your key's scopes returns 403 with {"detail": "This API key does not have the '<scope>' scope."}. There is no wildcard scope — a source added later is never automatically granted to existing keys.

Existing keys keep working. Scoping was introduced after both APIs already had customers on unscoped keys. Every key that was live at cutover was migrated to full access for the scopes that existed at that time, automatically and with no key-value change — nothing breaks and no action is needed on your side. Scoped (narrower) keys are opt-in from here: ask your Gumo contact if you want a new key limited to specific sources.
destination:booking is not on any key yet, including full-access ones. It's a separate scope from ota:booking, not implied by it — pricing one hotel and enumerating an entire city are different products with unit costs orders of magnitude apart. Since it post-dates every key issued so far, it is never granted implicitly by the "existing keys keep working" migration above; ask your Gumo contact to add it explicitly before your first call to Destination Search.
ota:goibibo is our newest scope and ships gated per environment. The same "existing keys keep working" migration does not reach it — it post-dates every key issued so far, same as destination:booking above. Ask your Gumo contact to add it, and see the Goibibo guide for the separate platform-wide gate that can still return 400 even once your key holds the scope.
Authorization header
X-API-Key: gsk_a1b2c3d4e5f6...   # Hotel API (Google Hotels + OTA rates)
X-API-Key: fsk_a1b2c3d4e5f6...   # Flight API (Google Flights)
  • 401 Unauthorized — missing, invalid, or deactivated key.
  • 403 Forbidden — key is valid but lacks the required scope.

Request a free developer trial to get your keys.

The job workflow

Every scraping endpoint is asynchronous. You submit a job, receive a job_id and a poll_url, then poll until the job reaches a terminal state:

  1. SubmitPOST …/scrape/ (or POST …/ota-price/) returns 202 with { job_id, status: "pending", poll_url }.
  2. PollGET the poll_url every ~2 seconds. status moves pending → processing → completed (or failed).
  3. Read — when status is completed, the result object holds the data.
Jobs poll on their own surface: Hotels → Meta jobs at /scrape/{job_id}/, Hotels → OTA jobs at /ota-price/{job_id}/, Hotels → Destination Search jobs at /destination-search/{job_id}/, Flights jobs (either source) at /flight-scraper/scrape/{job_id}/. Polling a job on the wrong endpoint returns 404.

Rate limits & quotas

Limits are enforced per API client and are configurable per plan. Defaults:

LimitDefaultWindow
Rate limit10 requestsper minute
Daily quota1,000 requestsper day (UTC)
Monthly quota20,000 requestsper billing cycle

"Per billing cycle" is not always the calendar month: each client has a billing_cycle_day (1–28) the monthly quota resets on. New clients are anchored to their sign-up day; clients provisioned before billing cycles existed run on day 1 — the calendar month, unchanged. GET /usage/'s billing_period block reports your account's actual window.

Exceeding any limit returns HTTP 429 with a descriptive detail, e.g. "Rate limit exceeded (10/min). Try again shortly."

Batch requests consume one unit per item. A batch of 20 hotels counts as 20 against every limit.
Rate Shop consumes one unit per cellhotels × otas × dates. A 10-hotel, 3-OTA, 30-date shop is 900 units. The whole matrix is priced against your quota before any work starts and refused as a unit if it won't fit, with the arithmetic in the error — never billed for a partial matrix.
Polling is free. Only job-submitting calls consume rate limit and quota — poll endpoints, batch results and /usage/ are never counted.

Errors

StatusMeaning
400Invalid input — validation error, with a per-field detail.
401Missing, invalid, or deactivated API key.
403Key is valid but lacks the scope for the requested source/scraper.
404Job not found (or not owned by your key).
429Rate limit or quota exceeded.
500Unexpected server error.
Fail-soft results. A scrape that finds nothing is not an HTTP error. Polls always return 200: a job ends completed with an empty result (e.g. no_results, sold_out: true) or failed with a human-readable error_message. Read each scraper's page for specifics.

Usage endpoint

Check your consumption against your quotas at any time. Available on both surfaces:

GET /api/v1/scraper/usage/?days=30
GET /api/v1/flight-scraper/usage/?days=30
GET /usage/
# Hotel API (Google Hotels + OTA rates)
curl "https://gumo.co.in/api/v1/scraper/usage/?days=30" \
  -H "X-API-Key: gsk_your_api_key"

# Flight API (Google Flights)
curl "https://gumo.co.in/api/v1/flight-scraper/usage/?days=30" \
  -H "X-API-Key: fsk_your_api_key"
200 OK
{
  "client": "Your Company Name",
  "billing_period": { "cycle_day": 1, "start": "2026-04-01", "end": "2026-04-30", "resets_on": "2026-05-01" },
  "lifetime": { "total_requests": 12450, "total_bandwidth_kb": 3245678.5 },
  "limits": { "rate_limit_per_minute": 10, "daily_quota": 1000, "monthly_quota": 20000 },
  "usage": [
    { "date": "2026-04-08", "request_count": 142, "success_count": 138,
      "failure_count": 4, "total_duration_seconds": 856.3, "total_bandwidth_kb": 36890.2 }
  ]
}

days is clamped into the 1–90 range (out-of-range values are adjusted, not rejected); a non-integer returns 400 (days must be an integer (1–90))

billing_period is the window "monthly" means for your account — the monthly quota is summed over your billing cycle, which starts on cycle_day of each month and resets on resets_on, the date your monthly quota springs back to the full amount. start and end are both inclusive. Identical shape on both APIs, so a customer of both reads one contract.

Surface difference: the bandwidth fields (lifetime.total_bandwidth_kb, per-day total_bandwidth_kb) exist on the Hotel API only. The Flight API usage response reports requests, successes, failures and durations — no bandwidth accounting. Bandwidth is the measured, compressed traffic the scrape moved through our proxies (response headers excluded); failed scrapes count what they spent before failing.

Client dashboard

A browser dashboard of your own scraping activity — submitted / succeeded / failed / in-flight counts as KPI cards, a time-series chart, and a PDF export. Sign in with the portal username/email + password you were provisioned (ask your Gumo contact), or with any of your active Hotel or Flight API keys. Either way the dashboard is scoped server-side to your data only, and access ends the moment your credentials are revoked on our side.

Destination searches aren't in the dashboard's counts yet — the KPI cards, time-series chart and PDF cover Google Hotels and OTA per-hotel jobs only. They do count toward the usage and quota figures on GET /usage/ above, so the two can disagree if you use Destination Search.
GET https://gumo.co.in/client/scrape-dashboard/

For programmatic access, the same stats are available as JSON or PDF using just your API key — no sign-in needed:

GET /client/scrape-dashboard/data/?range=7d
GET /client/scrape-dashboard/pdf/?range=7d
GET /client/scrape-dashboard/data/
curl "https://gumo.co.in/client/scrape-dashboard/data/?range=7d" \
  -H "X-API-Key: gsk_your_api_key"   # or an fsk_ key
ParamOptionalDescription
rangeyesQuick window ending now, e.g. 10m, 30m, 7d. Wins over start/end when present.
start, endyesYYYY-MM-DD or full ISO 8601. Ignored if range is set.
granularityyesminute | hour | day | month. Auto-picked from the window size when omitted (minute ≤3h, hour ≤7d, day ≤90d, month beyond).

With nothing supplied the window defaults to the last 7 days. Unrecognized values are ignored (not rejected) and reported back in a warnings array; the request still succeeds with the default window applied.

200 OK
{
  "series": [
    { "bucket": "2026-08-06T00:00:00+05:30", "label": "2026-08-06 00:00",
      "submitted": 42, "succeeded": 39, "failed": 2, "in_flight": 1 }
  ],
  "per_client": [
    { "client_id": 123, "client_name": "Your Company Name",
      "submitted": 312, "succeeded": 298, "failed": 14,
      "in_flight": 0, "success_rate": 95.5 }
  ],
  "totals": { "submitted": 312, "succeeded": 298, "failed": 14, "in_flight": 0, "success_rate": 95.5 },
  "meta": { "granularity": "hour", "start": "2026-08-06T00:00:00+05:30",
    "end": "2026-08-13T00:00:00+05:30", "client_id": 123, "range_key": "7d" }
}

per_client contains at most one row — your own — the dashboard endpoints never return another client's name, id or volume. bucket timestamps are UTC-offset ISO 8601; label is the same instant formatted for display in Asia/Kolkata.

/client/scrape-dashboard/pdf/ takes the same query params and streams a PDF (Content-Type: application/pdf) instead of JSON.

Free. Like /usage/, the dashboard page, JSON and PDF endpoints are never counted against your rate limit or quota.

Ready to dive in? Pick a guide: Google Flights · MakeMyTrip Flights · Google Hotels · Agoda · Booking.com · MakeMyTrip Hotels · Expedia · Goibibo · Destination Search · Rate Shop.