# Make your first purchase

This guide takes you from an OMSA :def[omsa-offer|offer] to a confirmed package after payment.

You will:

- Prepare a package directly from an offer.
- Use a draft package when the sale needs customisation.
- Confirm the package after external payment.

:::note

Eager to start experimenting with code? Explore the API spec directly at `https://developer.entur.no/apis/omsa/latest/openapi.json` (does not require auth).

:::

## Before you begin

To use this guide, you need to:

- Complete the [Search offers guide](/guides/omsa/search-offers) and keep an offer ID from the response.
- Use the OMSA dev base URL `https://api.dev.entur.io/omsa/v1`.

:::info

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

:::

## Choose a purchase flow

OMSA supports two ways to prepare an offer for purchase:

- Use `purchase-offers` to turn one or more offer IDs directly into a purchase-ready package.
- Use `select-offers` to create a draft package, make any required changes, then use `purchase-package` to make it purchase-ready.

Both flows continue with external payment and `confirm-package`. Use the direct flow for your first purchase. Use the custom draft flow when you need to add travellers, ancillary products, or assets before payment.

## Prepare a package directly

Send the offer ID from your `search-offers` response to the `purchase-offers` process. This skips the custom draft steps and returns a purchase-ready package.

::endpoint[omsa/purchaseOffersProcessHandler]

```json
{
  "inputs": {
    "type": "purchase_offers",
    "offerIds": [
      "a3509357-b5c2-4c7d-910a-11e638d48f4b"
    ]
  }
}
```

The response contains the resulting :def[omsa-package|package]. Store its `id` for payment and confirmation.

```json
{
  "type": "package",
  "id": "D92YGB7L",
  "status": "PENDING",
  "price": {
    "amount": 354,
    "currencyCode": "NOK"
  },
  "offers": [
    {
      "type": "offer",
      "id": "a3509357-b5c2-4c7d-910a-11e638d48f4b"
    }
  ]
}
```

Continue with [Take payment](#take-payment).

## Prepare a custom package

Use this flow when you must change the package before payment.

### Select the offer

Send the offer ID to the `select-offers` process. The response contains a draft package.

::endpoint[omsa/selectOffersHandler]

```json
{
  "inputs": {
    "type": "select_offers",
    "offerIds": [
      "a3509357-b5c2-4c7d-910a-11e638d48f4b"
    ]
  }
}
```

Keep the returned package `id`. You need it to purchase the package.

```json
{
  "type": "package",
  "id": "D92YGB7L",
  "status": "SELECTED",
  "price": {
    "amount": 354,
    "currencyCode": "NOK"
  },
  "offers": [
    {
      "type": "offer",
      "id": "a3509357-b5c2-4c7d-910a-11e638d48f4b"
    }
  ]
}
```

### Customise the package

Make any required changes while the package is in the draft sales phase. Depending on the offer and mobility operator, you can:

- Add or update travellers.
- Add ancillary products with `assign-ancillary`.
- Add assets with `assign-asset`.

The available changes depend on the mobility operator. Check the package response and OMSA API specification before presenting an option to the customer.

### Make the package purchase-ready

After making the required draft changes, send the package ID to the `purchase-package` process. This makes the package ready for payment.

::endpoint[omsa/purchasePackageProcessHandler]

```json
{
  "inputs": {
    "type": "package",
    "packageId": "D92YGB7L"
  }
}
```

The response contains the purchase-ready package. Store its `id` for payment and confirmation.

```json
{
  "type": "package",
  "id": "D92YGB7L",
  "status": "PENDING",
  "price": {
    "amount": 354,
    "currencyCode": "NOK"
  },
  "offers": [
    {
      "type": "offer",
      "id": "a3509357-b5c2-4c7d-910a-11e638d48f4b"
    }
  ]
}
```

## Take payment

Take payment through your payment integration. Payment happens outside OMSA, either with your chosen PSP or the Entur [Payment API](/apis/payment-partner).

Keep the OMSA package ID with the payment transaction. Continue only after payment succeeds.

## Confirm the package

Send the paid package ID to the `confirm-package` process. The process is idempotent. If a request times out, retry with the same package ID without creating a duplicate purchase.

::endpoint[omsa/confirmPackageProcessHandler]

```json
{
  "inputs": {
    "type": "package",
    "packageId": "D92YGB7L"
  }
}
```

The response contains the confirmed package.

```json
{
  "type": "package",
  "id": "D92YGB7L",
  "status": "CONFIRMED",
  "price": {
    "amount": 354,
    "currencyCode": "NOK"
  },
  "offers": [
    {
      "type": "offer",
      "id": "a3509357-b5c2-4c7d-910a-11e638d48f4b"
    }
  ]
}
```

Retrieve the package by ID if you need to check its latest status.

::endpoint[omsa/getPackage]

Confirm that:

- The request returns HTTP `200`.
- The package `id` matches the package returned by the purchase process.
- The package status is `CONFIRMED`.
- The price and offers match the purchase.

:::warning

Do not confirm the purchase to the customer before the package status is `CONFIRMED`.

:::

## Troubleshoot the purchase

- If the offer is no longer valid, run `search-offers` again and purchase a new offer.
- If the package is `EXPIRED`, create a new package from a current offer.
- If `confirm-package` returns `409 ORDER_NOT_SETTLED`, payment has not settled yet. The package stays `PENDING`. Wait for payment to succeed, then retry.
- If a request returns `423 PACKAGE_LOCKED`, another request is modifying the package. Retry shortly.
- If a request returns `401` or `403`, check the access token and partner permissions.
- If a request fails unexpectedly, include the `X-Correlation-ID` response header when contacting Entur support.

## Next steps

After confirming the purchase, retrieve and deliver the travel documents for the package.
