Skip to content
ScoutingAPI
Docs

Response & error envelope

Every REST response is one of exactly three envelope shapes — success (200), async-accepted (202) and error (4xx/5xx). Learn it once; it is identical on every endpoint.

Success — HTTP 200

Only data varies by endpoint (see the unified schema). The meta block around it is the same everywhere.

200 OK
{
  "data": [ /* Property[] | object — the endpoint-specific payload */ ],
  "meta": {
    "requestId": "req_8sf…",
    "platforms": ["airbnb", "booking"],
    "cached": false,
    "partial": false,
    "creditsCharged": 8,
    "currency": "USD",
    "pagination": { "limit": 20, "cursor": null, "nextCursor": "eyJ…", "hasMore": true },
    "platformResults": [
      { "platform": "airbnb", "status": "ok", "creditsCharged": 4, "cached": false, "count": 18 },
      { "platform": "booking", "status": "ok", "creditsCharged": 4, "cached": true, "count": 20 }
    ],
    "warnings": []
  }
}

The meta block

FieldMeaning
requestIdUnique req_-prefixed id for this request; quote it in support tickets. Also the X-Request-Id header.
platformsThe platform(s) actually queried, in the order resolved.
cachedtrue only if the entire response was served from cache. Per-platform flags live in platformResults[].
partialtrue if a fan-out had ≥1 platform fail while ≥1 succeeded (see below).
creditsChargedTotal credits across platforms. 0 on any failed/empty leg and on any error.
currencyThe currency of monetary values in data — always echoed, never inferred.
paginationCursor block { limit, cursor, nextCursor, hasMore } on list endpoints; null on single-object ones.
platformResults[]One row per platform queried in a fan-out: status, creditsCharged, cached, count, error.
warnings[]Non-fatal advisories (may be empty). Tolerate unknown codes.

Async accepted — HTTP 202

When a live scrape is projected to run longer than ~8 seconds, the request returns a job handle instead of blocking. No credits are charged on the 202 — the work is billed once, on completion, via /v1/jobs/{jobId}. Cache hits are always served synchronously.

202 Accepted
{
  "data": { "jobId": "job_3kf…", "status": "pending", "pollUrl": "/v1/jobs/job_3kf…", "estimatedSeconds": 25 },
  "meta": { "requestId": "req_…", "creditsCharged": 0, "platforms": ["vrbo"] }
}

Error — 4xx / 5xx

A response never carries both data and error. Field semantics — and the complete catalog — are on the errors page. creditsCharged is always 0 on an error.

400 Bad Request
{
  "error": {
    "type": "invalid_request",
    "code": "missing_parameter",
    "message": "checkOut is required when checkIn is provided.",
    "param": "checkOut",
    "requestId": "req_…",
    "creditsCharged": 0,
    "retryable": false,
    "docUrl": "https://scoutingapi.com/docs/errors/missing_parameter"
  }
}

Partial fan-out semantics

This is the most important non-obvious rule in the envelope. A fan-out queries N platforms concurrently and merges their normalized results. If every platform fails, it is a top-level 503. But if at least one succeeds and at least one fails, you get HTTP 200 with:

Partial success
// HTTP 200 — airbnb succeeded, vrbo was blocked
{
  "data": [ /* 18 Airbnb Property objects only */ ],
  "meta": {
    "platforms": ["airbnb", "vrbo"],
    "partial": true,
    "creditsCharged": 4,
    "platformResults": [
      { "platform": "airbnb", "status": "ok", "creditsCharged": 4, "cached": false, "count": 18 },
      { "platform": "vrbo", "status": "failed", "creditsCharged": 0, "cached": false, "count": 0,
        "error": { "type": "upstream_unavailable", "code": "actor_blocked",
                   "message": "All Vrbo actors failed or were blocked for this request." } }
    ],
    "warnings": [
      { "code": "platform_failed", "platform": "vrbo", "message": "Vrbo results omitted; not charged." }
    ]
  }
}

A failed platform is always free