Solera API (v1)

Download OpenAPI specification:

Solera is Data Mojito's travel data API. It returns flight and hotel pricing and availability — cash fares and loyalty award fares alike — extracted live from airline, hotel and meta-search providers.

Two ways to get the same data:

Service Use it when
Realtime TravelSearchService Someone is waiting. Results stream back per source as each one finishes.
Scheduled / batch TravelJobService Nobody is waiting. Submit, poll, collect.

Both cover flights and hotels, and both return the identical result payload — so you model the data once and choose the delivery mode per use case.

The Solera data model

Every result, from every source, in both delivery modes, is shaped by one canonical model. A field means the same thing regardless of which provider produced it, so comparing two airlines is a matter of comparing two structs, not writing a mapping layer per provider.

Each source's payload is an envelope of three parts:

Block What it holds
capture How the result was produced — collector, version, timestamp, device, point of sale
resolved_query What was actually searched for, after any provider-side normalization
offers What was found — the priced itineraries or rates

capture and resolved_query are not decoration. The same route scanned under a different point_of_sale or device is legitimately a different price, and resolved_query records what the provider really searched for, which is not always what you asked for. Reconcile against them before comparing results across sources.

Field naming

One thing to get right before you write a parser: Solera names fields in snake_case, and the JSON on the wire uses camelCase.

Protobuf's canonical JSON mapping lower-camel-cases field names, so the field display_price arrives as displayPrice, award_points as awardPoints, and source_ids is sent as sourceIds. The schemas below are labelled with both: the property name is the JSON name you will actually see, and the title above it is the field's name in the model.

Requests accept either spelling; responses always use camelCase.

Cash and rewards

Cash and award pricing sit side by side on every flight and hotel result, rather than in separate response shapes:

  • price_modeCASH, AWARD or MIXED. Read this first; it determines which of the price fields is meaningful.
  • display_price / currency — the cash price as displayed.
  • award_points / loyalty_program — the award price. Points from different programmes are not comparable, so never read award_points without its programme.
  • award_surcharge — cash still payable on an award booking (taxes, surcharges, resort fees). Carries its own currency. An award fare is rarely points-only, so ignoring this understates the real cost.

Protocol

Solera is a Connect RPC API. Every operation is a POST to /{proto.package}.{Service}/{Method} — paths are never parameterized, and there are no GET/PUT/DELETE variants. It is not a REST API and does not pretend to be one.

The same endpoints speak three protocols, selected by Content-Type:

Protocol Content-Type Notes
Connect, unary application/json Plain JSON over HTTP/1.1 — usable straight from curl
Connect, streaming application/connect+json JSON messages in Connect's length-prefixed envelope
gRPC / gRPC-Web application/grpc* Binary protobuf; requires HTTP/2

The gRPC content types are listed on each operation for completeness, but this document does not describe their binary framing — use the .proto, or the server's gRPC reflection, for that.

Streaming operations

SearchFlights and SearchHotels are server-streaming: one response is emitted per requested source_id as that provider finishes, in completion order rather than request order. The stream closes once every requested source has produced a result.

OpenAPI has no vocabulary for this. The response schema shown below is the schema of a single message in the stream, not of the whole HTTP response body — the real body is a sequence of those messages inside Connect's envelope frames. Read the schema as "what each chunk looks like", and the operation description as the authority on how many chunks arrive.

If your infrastructure will not hold a connection open for the length of a scan — seconds, not milliseconds — use TravelJobService instead. Same data, no long-lived connection.

Errors

Two layers, and confusing them is the most common integration mistake.

RPC errors use the Connect error shape (code, message, details) with an HTTP status derived from the code — see the connect.error schema, present as the default response on every operation. These mean the call itself failed.

Source-level failures are not RPC errors. A provider that times out, is unreachable, or returns nothing still yields a normal 200 response carrying that source's status and error. A multi-source search where every source failed is still a successful call. The per-source status field is the authoritative outcome — check it on every result before reading data.

Note that NO_AVAILABILITY is a success: the search ran cleanly and the route or property genuinely has nothing on sale. Do not retry it as though it were a failure.

Validation

Request constraints are declared in the .proto with protovalidate and enforced server-side before any handler runs. The constraints rendered on each schema (minItems, minimum, required, …) are generated from those same declarations, so they are the rules the server actually applies — not documentation-only hints. A violation returns invalid_argument naming the field that failed.

Testing without live providers

Negative source_id values address the mock collector, which synthesizes results deterministically without touching the live fleet: 0 is a generic mock, and -1 through -30 each mock the correspondingly numbered real source. Use them to exercise every success and failure path during integration — including the ones that are hard to provoke on purpose, like SOURCE_BLOCKED and THROTTLER_TIMEOUT.

TravelJobService

Asynchronous travel search: submit a job, poll for completion, fetch the results.

Same collectors, same payloads and same source semantics as TravelSearchService — the only difference is delivery. Nothing is held open: you submit, you get a job_id back immediately, and you come back for the results whenever you like.

Use this for scheduled and batch work: overnight refreshes, rate monitoring across many routes, anything running where no user is waiting, and anything behind infrastructure that will not hold a streaming connection open for the length of a scan.

The lifecycle is:

  1. SubmitSearch — enqueue the work, receive a job_id.
  2. GetSearchJob — poll until status is terminal. Honour retry_after_ms; it reflects real queue depth.
  3. GetSearchResults — page through the completed sources' payloads.

Results are retained for a limited window after completion (see expires_at) and then deleted. Fetch what you need before then.

CancelSearchJob

Cancels a job that has not yet reached a terminal state. Sources already completed keep their results and stay fetchable; sources not yet started are dropped.

header Parameters
Connect-Protocol-Version
required
number (Connect-Protocol-Version)
Value: 1

Define the version of the Connect protocol

Value: 1
Connect-Timeout-Ms
number (Connect-Timeout-Ms)

Define the timeout, in ms

Request Body schema: application/json
required
jobId
string (job_id) non-empty

Responses

Request samples

Content type
application/json
{
  • "jobId": "string"
}

Response samples

Content type
application/json
{
  • "jobId": "string",
  • "status": "UNSPECIFIED",
  • "completedSources": 0
}

GetSearchJob

Reports a job's progress. Poll this until status is terminal (SUCCEEDED, PARTIAL, FAILED, EXPIRED or CANCELLED).

Respect retry_after_ms rather than polling on a fixed interval — polling faster does not make a scan finish sooner and will be rate limited.

header Parameters
Connect-Protocol-Version
required
number (Connect-Protocol-Version)
Value: 1

Define the version of the Connect protocol

Value: 1
Connect-Timeout-Ms
number (Connect-Timeout-Ms)

Define the timeout, in ms

Request Body schema: application/json
required
jobId
string (job_id) non-empty

Responses

Request samples

Content type
application/json
{
  • "jobId": "string"
}

Response samples

Content type
application/json
{
  • "jobId": "string",
  • "requestId": "string",
  • "status": "UNSPECIFIED",
  • "totalSources": 0,
  • "completedSources": 0,
  • "failedSources": 0,
  • "retryAfterMs": 0,
  • "error": {
    • "code": "UNSPECIFIED",
    • "message": "string",
    • "remark": "string"
    },
  • "submittedAt": "2023-01-15T01:30:15.01Z",
  • "completedAt": "2023-01-15T01:30:15.01Z",
  • "expiresAt": "2023-01-15T01:30:15.01Z"
}

GetSearchResults

Fetches a completed job's results, one page at a time.

Callable as soon as completed_sources is non-zero, so a long-running job can be drained incrementally rather than only at the end — sources already finished are returned even while others are still running.

header Parameters
Connect-Protocol-Version
required
number (Connect-Protocol-Version)
Value: 1

Define the version of the Connect protocol

Value: 1
Connect-Timeout-Ms
number (Connect-Timeout-Ms)

Define the timeout, in ms

Request Body schema: application/json
required
jobId
string (job_id) non-empty
pageSize
integer or null <int32> (page_size) [ 1 .. 100 ]

Maximum sources to return in this page. Defaults to 25 when omitted.

pageToken
string or null (page_token)

next_page_token from the previous page. Omit for the first page.

sourceIds
Array of integers <int32> (source_ids) [ items <int32 > ]

Return only these source IDs. Omit for all of them. Useful for draining a running job source by source as each one finishes.

Responses

Request samples

Content type
application/json
{
  • "jobId": "string",
  • "pageSize": 1,
  • "pageToken": "string",
  • "sourceIds": [
    • 0
    ]
}

Response samples

Content type
application/json
{
  • "jobId": "string",
  • "status": "UNSPECIFIED",
  • "flightResults": [
    • {
      • "sourceId": 0,
      • "sourceName": "string",
      • "status": "UNSPECIFIED",
      • "error": {
        },
      • "data": {
        },
      • "metadata": {
        }
      }
    ],
  • "hotelResults": [
    • {
      • "sourceId": 0,
      • "sourceName": "string",
      • "status": "UNSPECIFIED",
      • "error": {
        },
      • "data": {
        },
      • "metadata": {
        }
      }
    ],
  • "nextPageToken": "string",
  • "totalResults": 0
}

SubmitSearch

Enqueues a search and returns immediately with a job identifier.

Submission does not validate provider availability — only the request itself. A job that was accepted here can still complete with every source failed.

header Parameters
Connect-Protocol-Version
required
number (Connect-Protocol-Version)
Value: 1

Define the version of the Connect protocol

Value: 1
Connect-Timeout-Ms
number (Connect-Timeout-Ms)

Define the timeout, in ms

Request Body schema: application/json
required
One of
required
object (search.v1.FlightSearchRequest)

What to search for, and where to search for it.

required
object (search.v1.FlightSearchParameters)

The travel itinerary being priced. flight_search_parameters.roundtrip_return_date // return_date is required for roundtrip searches flight_search_parameters.route // source_iata and destination_iata must differ

currency
string (currency)

ISO 4217 code to quote cash prices in, e.g. "USD". Where the provider cannot quote in this currency, it quotes in its own and reports that in each result's currency field — so always read the currency off the result, never assume it matches what you requested.

sourceIata
string (source_iata) non-empty

Origin airport IATA code, e.g. "JFK".

destinationIata
string (destination_iata) non-empty

Destination airport IATA code, e.g. "LHR". Must differ from source_iata.

departureDate
string (departure_date) non-empty

Outbound date, "YYYY-MM-DD".

returnDate
string or null (return_date)

Return date, "YYYY-MM-DD". Required when is_roundtrip is true, ignored otherwise.

pointOfSale
string (point_of_sale)

Point of sale to search under, as an ISO 3166-1 alpha-2 country code, e.g. "US". Materially affects both cash pricing and award availability.

adults
integer <int32> (adults) >= 1

At least one adult is required.

youngAdults
integer or null <int32> (young_adults)
children
integer or null <int32> (children)
infants
integer or null <int32> (infants)
maxStops
integer <int32> (max_stops)

Maximum acceptable stops. 0 requests non-stop only. Providers treat this as a filter, so a restrictive value can legitimately produce zero results.

isRoundtrip
boolean (is_roundtrip)

When true, return_date must be set.

cabinClass
string (search.v1.FlightSearchParameters.CabinClass)
Enum: "UNSPECIFIED" "BUSINESS" "ECONOMY" "PREMIUM_ECONOMY" "FIRST"

Nested (rather than declared at package scope) so its values need no type-name prefix to stay unique — see ErrorDetail.ErrorCode for the reasoning.

requestId
string (request_id)

Caller-supplied idempotency and correlation key. Echoed on every response and recorded in platform telemetry — send a unique value per logical search and quote it in support requests.

sourceIds
Array of integers <int32> (source_ids) non-empty [ items <int32 > >= -30 ]

Sources to search, by ID (e.g. [5, 12, 19]). At least one is required.

Each requested source is dispatched independently and concurrently, and produces exactly one response — a source that fails does not prevent the others from returning. Source IDs are issued per account; ask for the catalogue that applies to yours.

Negative IDs address the mock source, which synthesizes results deterministically without touching the live collector fleet, so you can exercise every success and failure path during integration: 0 is a generic mock, and -1 through -30 each mock the correspondingly numbered real source.

callbackUrl
string or null (callback_url)

URL to POST a notification to when the job reaches a terminal state, so you can skip polling entirely.

The callback carries the job_id and final status only, never the results — fetch those with GetSearchResults. Delivery is at-least-once, so make your handler idempotent, and keep polling as a fallback: a callback that cannot be delivered is retried for a limited period and then abandoned, while the job's results remain fetchable regardless.

resultTtlSeconds
integer or null <int32> (result_ttl_seconds) [ 60 .. 604800 ]

How long to keep the results available for after completion. Clamped to your account's maximum retention; omit to use the account default.

Responses

Request samples

Content type
application/json
Example
{
  • "callbackUrl": "string",
  • "resultTtlSeconds": 60,
  • "flightSearch": {
    • "requestId": "string",
    • "sourceIds": [
      • -30
      ],
    • "parameters": {
      • "currency": "string",
      • "sourceIata": "string",
      • "destinationIata": "string",
      • "departureDate": "string",
      • "returnDate": "string",
      • "pointOfSale": "string",
      • "adults": 1,
      • "youngAdults": 0,
      • "children": 0,
      • "infants": 0,
      • "maxStops": 0,
      • "isRoundtrip": true,
      • "cabinClass": "UNSPECIFIED"
      }
    }
}

Response samples

Content type
application/json
{
  • "jobId": "string",
  • "requestId": "string",
  • "status": "UNSPECIFIED",
  • "totalSources": 0,
  • "retryAfterMs": 0,
  • "submittedAt": "2023-01-15T01:30:15.01Z"
}

TravelSearchService

Realtime travel search.

Both RPCs are server-streaming: you send one request naming several sources, and results arrive one source at a time as each collector finishes. Use this when a caller is waiting on the answer and you want to show the first results without waiting for the slowest provider.

Sources are dispatched concurrently and are independent of one another. A source that fails, times out or finds nothing still produces a response carrying its status and error — it never fails the call or suppresses the other sources. That means a stream can complete with every source having failed, and the RPC will still report success; the per-source status is the authoritative outcome, not the RPC's.

Responses arrive in completion order, not request order. Correlate on source_id, and treat the stream as complete only when it closes — not when a particular source arrives.

A scan takes seconds, and a stream is held open for its whole duration. If your caller cannot hold a connection that long — a batch job, a scheduled refresh, or anything behind a proxy with an aggressive idle timeout — use TravelJobService instead, which does the same work and lets you poll for the result.

Searches flights across the requested sources, streaming one FlightSourceResponse per source as its results become available.

Covers both cash and award pricing: each result's price_mode says which applies, with display_price carrying cash and award_points carrying rewards.

header Parameters
Connect-Protocol-Version
required
number (Connect-Protocol-Version)
Value: 1

Define the version of the Connect protocol

Value: 1
Connect-Timeout-Ms
number (Connect-Timeout-Ms)

Define the timeout, in ms

Request Body schema:
required
required
object (search.v1.FlightSearchParameters)

The travel itinerary being priced. flight_search_parameters.roundtrip_return_date // return_date is required for roundtrip searches flight_search_parameters.route // source_iata and destination_iata must differ

currency
string (currency)

ISO 4217 code to quote cash prices in, e.g. "USD". Where the provider cannot quote in this currency, it quotes in its own and reports that in each result's currency field — so always read the currency off the result, never assume it matches what you requested.

sourceIata
string (source_iata) non-empty

Origin airport IATA code, e.g. "JFK".

destinationIata
string (destination_iata) non-empty

Destination airport IATA code, e.g. "LHR". Must differ from source_iata.

departureDate
string (departure_date) non-empty

Outbound date, "YYYY-MM-DD".

returnDate
string or null (return_date)

Return date, "YYYY-MM-DD". Required when is_roundtrip is true, ignored otherwise.

pointOfSale
string (point_of_sale)

Point of sale to search under, as an ISO 3166-1 alpha-2 country code, e.g. "US". Materially affects both cash pricing and award availability.

adults
integer <int32> (adults) >= 1

At least one adult is required.

youngAdults
integer or null <int32> (young_adults)
children
integer or null <int32> (children)
infants
integer or null <int32> (infants)
maxStops
integer <int32> (max_stops)

Maximum acceptable stops. 0 requests non-stop only. Providers treat this as a filter, so a restrictive value can legitimately produce zero results.

isRoundtrip
boolean (is_roundtrip)

When true, return_date must be set.

cabinClass
string (search.v1.FlightSearchParameters.CabinClass)
Enum: "UNSPECIFIED" "BUSINESS" "ECONOMY" "PREMIUM_ECONOMY" "FIRST"

Nested (rather than declared at package scope) so its values need no type-name prefix to stay unique — see ErrorDetail.ErrorCode for the reasoning.

requestId
string (request_id)

Caller-supplied idempotency and correlation key. Echoed on every response and recorded in platform telemetry — send a unique value per logical search and quote it in support requests.

sourceIds
Array of integers <int32> (source_ids) non-empty [ items <int32 > >= -30 ]

Sources to search, by ID (e.g. [5, 12, 19]). At least one is required.

Each requested source is dispatched independently and concurrently, and produces exactly one response — a source that fails does not prevent the others from returning. Source IDs are issued per account; ask for the catalogue that applies to yours.

Negative IDs address the mock source, which synthesizes results deterministically without touching the live collector fleet, so you can exercise every success and failure path during integration: 0 is a generic mock, and -1 through -30 each mock the correspondingly numbered real source.

Responses

Request samples

Content type
{
  • "requestId": "string",
  • "sourceIds": [
    • -30
    ],
  • "parameters": {
    • "currency": "string",
    • "sourceIata": "string",
    • "destinationIata": "string",
    • "departureDate": "string",
    • "returnDate": "string",
    • "pointOfSale": "string",
    • "adults": 1,
    • "youngAdults": 0,
    • "children": 0,
    • "infants": 0,
    • "maxStops": 0,
    • "isRoundtrip": true,
    • "cabinClass": "UNSPECIFIED"
    }
}

Response samples

Content type
{
  • "sourceId": 0,
  • "sourceName": "string",
  • "status": "UNSPECIFIED",
  • "error": {
    • "code": "UNSPECIFIED",
    • "message": "string",
    • "remark": "string"
    },
  • "data": {
    • "hasOffers": true,
    • "offerCount": 0,
    • "capture": {
      • "collector": "string",
      • "collectorVersion": "string",
      • "timestamp": "2023-01-15T01:30:15.01Z",
      • "device": "string",
      • "pointOfSale": "string"
      },
    • "resolvedQuery": {
      • "originIataCode": "string",
      • "destinationIataCode": "string",
      • "outboundDate": "string",
      • "inboundDate": "string",
      • "adults": 0,
      • "youngAdults": 0,
      • "children": 0,
      • "infants": 0,
      • "cabinClass": "string",
      • "currency": "string",
      • "pointOfSale": "string"
      },
    • "offers": [
      • {
        }
      ]
    },
  • "metadata": {
    • "executionId": "string",
    • "scanStartTime": "2023-01-15T01:30:15.01Z",
    • "scanEndTime": "2023-01-15T01:30:15.01Z",
    • "executionDurationMs": 0,
    • "deepLink": "string",
    • "requestedCurrency": "string"
    }
}

Searches hotels across the requested sources, streaming one StaySourceResponse per source as its results become available.

Covers both cash and award pricing, on the same price_mode convention as SearchFlights. Note that one property offering several rate plans yields several results — group on property.property_code.

header Parameters
Connect-Protocol-Version
required
number (Connect-Protocol-Version)
Value: 1

Define the version of the Connect protocol

Value: 1
Connect-Timeout-Ms
number (Connect-Timeout-Ms)

Define the timeout, in ms

Request Body schema:
required
required
object (search.v1.HotelSearchParameters)

The stay being priced. hotel_search_parameters.destination // either destination or property_code must be set hotel_search_parameters.stay_dates // check_out_date must be later than check_in_date

currency
string (currency)

ISO 4217 code to quote cash prices in, e.g. "USD". Read the currency off each result rather than assuming this was honoured.

destination
string (destination)

Where to search: a city name, IATA city code, or provider region identifier, e.g. "Bangkok" or "BKK". Either this or property_code must be set; supplying both narrows the search to that property in that market.

propertyCode
string or null (property_code)

Search one specific property rather than a market, by the provider's own property identifier. Use this for rate monitoring of a known hotel.

checkInDate
string (check_in_date) non-empty

Arrival date, "YYYY-MM-DD".

checkOutDate
string (check_out_date) non-empty

Departure date, "YYYY-MM-DD". Must be later than check_in_date. The number of nights is the difference between the two.

rooms
integer <int32> (rooms) >= 1

Rooms required. Providers price per room, and a multi-room search is not always the per-room price multiplied out.

adults
integer <int32> (adults) >= 1

Adults across all rooms. At least one is required.

children
integer or null <int32> (children)
childAges
Array of integers <int32> (child_ages) [ items <int32 > ]

Ages of the accompanying children, in years. Several providers price children by age and will reject or silently re-price a search that omits them, so supply one entry per child in children.

pointOfSale
string (point_of_sale)

Point of sale, as an ISO 3166-1 alpha-2 country code, e.g. "US". Materially affects both cash rates and award availability.

minStarRating
integer <int32> (min_star_rating) [ 0 .. 5 ]

Restrict to a minimum star rating, 1-5. Zero means no restriction.

requestId
string (request_id)

Caller-supplied idempotency and correlation key. Echoed on every response and recorded in platform telemetry.

sourceIds
Array of integers <int32> (source_ids) non-empty [ items <int32 > >= -30 ]

Sources to search, by ID. At least one is required. Dispatched independently and concurrently, one response per source. Negative IDs address the mock collector — see FlightSearchRequest.source_ids.

Responses

Request samples

Content type
{
  • "requestId": "string",
  • "sourceIds": [
    • -30
    ],
  • "parameters": {
    • "currency": "string",
    • "destination": "string",
    • "propertyCode": "string",
    • "checkInDate": "string",
    • "checkOutDate": "string",
    • "rooms": 1,
    • "adults": 1,
    • "children": 0,
    • "childAges": [
      • 0
      ],
    • "pointOfSale": "string",
    • "minStarRating": 5
    }
}

Response samples

Content type
{
  • "sourceId": 0,
  • "sourceName": "string",
  • "status": "UNSPECIFIED",
  • "error": {
    • "code": "UNSPECIFIED",
    • "message": "string",
    • "remark": "string"
    },
  • "data": {
    • "hasOffers": true,
    • "offerCount": 0,
    • "capture": {
      • "collector": "string",
      • "collectorVersion": "string",
      • "timestamp": "2023-01-15T01:30:15.01Z",
      • "device": "string",
      • "pointOfSale": "string"
      },
    • "resolvedQuery": {
      • "destination": "string",
      • "propertyCode": "string",
      • "checkInDate": "string",
      • "checkOutDate": "string",
      • "nights": 0,
      • "rooms": 0,
      • "adults": 0,
      • "children": 0,
      • "childAges": [
        ],
      • "currency": "string",
      • "pointOfSale": "string"
      },
    • "offers": [
      • {
        }
      ]
    },
  • "metadata": {
    • "executionId": "string",
    • "scanStartTime": "2023-01-15T01:30:15.01Z",
    • "scanEndTime": "2023-01-15T01:30:15.01Z",
    • "executionDurationMs": 0,
    • "deepLink": "string",
    • "requestedCurrency": "string"
    }
}