# Search offers
import { Accordion, AccordionContent, AccordionItem, AccordionTrigger } from "zudoku/ui/Accordion";

This guide gets you from zero to your first OMSA :def[omsa-offer|offer].

You will:

- Model who is travelling.
- Send your first `search-offers` process request.
- Understand the basics of an OMSA `OfferCollection` response.

:::note

Eager to start experimenting with code? Explore the API spec directly at `https://api.dev.entur.io/omsa/v1/api` (does not require auth).

:::

## Before you begin
To use this guide, you need to:

- Be an authorised Entur partner.
- Have OAuth2 client credentials (`client_id` and `client_secret`).
- Have header values for :def[Entur-Distribution-Channel] and :def[Entur-POS].
- Use the OMSA dev base URL `https://api.dev.entur.io/omsa/v1`.

:::info

Read more about authentication [here](/docs/authentication#partner-apis).

:::

## 1. Specify who is travelling
When searching for offers, OMSA supports two traveller models:

- `individual_traveller`: an identifiable traveller (with specific attributes such as age, name, and possibly other personal details).
- `user_profile`: an anonymous traveller profile with a count.

You can use one of them, or both in the same request.

```json
{
  "travellers": [
    {
      "type": "individual_traveller",
      "id": "9f7f69ec-d68c-4751-8ec4-fd059f820cb8",
      "age": 30
    }
  ],
  "profiles": [
    {
      "type": "user_profile",
      "id": "1c9b2b5a-f291-404b-8235-50641ef2b733",
      "ageGroup": "ADULT",
      "count": 1
    }
  ]
}
```

## 2. Search for your first offer
Send your first request to `https://api.dev.entur.io/omsa/v1/processes/search-offers/execute`.

OMSA supports several place models in `specification`, most commonly:

- Fare zones (`KOL:FareZone:*`)
- Stop places (`NSR:StopPlace:*`)
- GPS coordinates (`GPS:lat,long[,alt]`)

:::info

These place references are used throughout the Entur platform and are based on :def[NeTEx] concepts. Read about the :def[FareZone] and :def[StopPlace] concepts, or see all accepted formats for OMSA :def[omsa-place-id|Place ID].

:::

<Accordion type="single" collapsible className="not-prose">
  <AccordionItem value="search-request-farezone">
    <AccordionTrigger>Example request (FareZone to FareZone)</AccordionTrigger>
    <AccordionContent>
      ```bash
      --header "Authorization: Bearer <ACCESS_TOKEN>" \
      --header "Accept-Language: en-GB" \
      --header "Content-Type: application/json" \
      --header "Entur-Distribution-Channel: ORG:DistributionChannel:App" \
      --header "Entur-POS: ORG-Web" \
      ```
      ```json
      {
        "inputs": {
          "type": "search_offer",
          "specification": {
            "from": {
              "placeId": "ORG:FareZone:1"
            },
            "to": {
              "placeId": "ORG:FareZone:3"
            }
          },
          "travellers": [
            {
              "id": "9f7f69ec-d68c-4751-8ec4-fd059f820cb8",
              "type": "individual_traveller",
              "fullName": "Ola Nordmann",
              "age": 30
            }
          ]
        }
      }
      ```
    </AccordionContent>
  </AccordionItem>

  <AccordionItem value="search-request-stopplace">
    <AccordionTrigger>Example request (StopPlace to StopPlace with profile)</AccordionTrigger>
    <AccordionContent>
      ```bash
      --header "Authorization: Bearer <ACCESS_TOKEN>" \
      --header "Accept-Language: en-GB" \
      --header "Content-Type: application/json" \
      --header "Entur-Distribution-Channel: ORG:DistributionChannel:App" \
      --header "Entur-POS: ORG-Web" \
      ```
      ```json
      {
        "inputs": {
          "type": "search_offer",
          "timestamp": "2026-04-24T09:00:00+02:00",
          "specification": {
            "from": {
              "placeId": "NSR:StopPlace:28434"
            },
            "to": {
              "placeId": "NSR:StopPlace:61291"
            },
            "startTime": "2026-04-24T10:00:00+02:00",
            "endTime": "2026-04-24T11:00:00+02:00"
          },
          "travellers": [
            {
              "type": "individual_traveller",
              "id": "9f7f69ec-d68c-4751-8ec4-fd059f820cb8",
              "fullName": "Ola Nordmann",
              "age": 30
            }
          ],
          "profiles": [
            {
              "type": "user_profile",
              "id": "1c9b2b5a-f291-404b-8235-50641ef2b733",
              "ageGroup": "ADULT",
              "count": 1
            }
          ]
        }
      }
      ```
    </AccordionContent>
  </AccordionItem>
</Accordion>

:::note

Please use `FareZone` in your application. Entur still supports the alternative spelling `TariffZone`, but note that this spelling is deprecated.

:::


## 3. Understand the response
Confirm that:

- The request returns HTTP `200`.
- The response contains at least one :def[omsa-offer|offer].
- Returned offers match expected :def[omsa-place-id|place ID]s and traveller inputs.

### Example response
```json
{
  "type": "OfferCollection",
  "offers": [
    {
      "id": "a3509357-b5c2-4c7d-910a-11e638d48f4b",
      "type": "offer",
      "properties": {
        "legs": [
          {
            "id": "a3509357-b5c2-4c7d-910a-11e638d48f4b",
            "type": "leg",
            "sequenceNumber": 1,
            "traveller": "9f7f69ec-d68c-4751-8ec4-fd059f820cb8",
            "state": "NOT_STARTED",
            "price": {
              "amount": 354.0,
              "currencyCode": "NOK"
            },
            "products": [
              "KOL:PreassignedFareProduct:4e913d65"
            ]
          }
        ],
        "products": [
          {
            "type": "product",
            "productId": {
              "productId": "KOL:PreassignedFareProduct:4e913d65",
              "name": "Kolumbus 7-day ticket"
            },
            "productName": "Kolumbus 7-day ticket"
          }
        ],
        "price": {
          "amount": 354.0,
          "currencyCode": "NOK"
        }
      }
    }
  ]
}
```

OMSA returns offers with `Leg` objects, even for simple `Zone`-`Zone` or `StopPlace`-`StopPlace` searches. In these cases, the leg represents a single traveller on a single product. To see which traveller belongs to which product and price, check the legs.

:::warning

If requests fail with `401` or `403`, verify token scopes and header values before retrying.

:::

### Troubleshooting tips
- If you receive an empty `offers` array, check that your `specification` parameters (place IDs, time range) align with available data in the dev environment.
- Use the OMSA API spec and error messages to debug issues. Common errors include invalid place IDs, duplicate traveller IDs, or missing required fields and headers.
- For authentication issues, ensure your OAuth2 token is valid and has the necessary scopes for OMSA access and the distribution channel and POS you are using.
- If you encounter unexpected errors or need further assistance, contact Entur support with details of your request and response for help. Include the `X-Correlation-ID` from your response headers to help us trace the problematic requests.

# Next steps
- Select and purchase an offer using the `select-offer` and `purchase-package` process endpoints (link coming soon).
- Apply discounts for eligible travellers with `entitlements`, e.g. seniors or students (link coming soon).
- Advanced `search-offers` requests, e.g. with a `TripPattern` from the Entur Journey Planner or a group of travellers (link coming soon).