> For the complete documentation index, see [llms.txt](https://partner-docs.covergenius.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://partner-docs.covergenius.com/offers/guides/multi-step-session-tracking.md).

# Multi-Step Session Tracking

## Overview

When building multi-step booking journeys such as offering coverage at search, updating options at checkout, and repricing before payment, each interaction typically generates a unique offer instance `id`.

Without session tracking, every request appears as an isolated event. This forces you to maintain external tracking maps and distorts reporting by counting a single customer's journey as multiple separate offer requests.

The Session Tracking capability introduces `session_id`, a single correlation ID maintained across your entire customer flow.

{% stepper %}
{% step %}
**Omit on Initial Request**

Send your initial `/offers` without a `session_id`. Offers generates a unique `session_id` and returns it in the response payload.
{% endstep %}

{% step %}
**Echo Back on Subsequent Requests**

Pass the returned `session_id` in `partner.metadata.session_id` on every subsequent API call for that customer journey (e.g., checkout, repricing).
{% endstep %}

{% step %}
**Maintain Independent Selection Logic**

Offers dynamically evaluates the current business context on each step, returning refreshed pricing or updated offers while binding all calls under one session.
{% endstep %}
{% endstepper %}

## How It Works

Understanding how identifiers interact throughout a multi-step journey helps ensure proper implementation:

| **Identifier**    | **Uniqueness Scope**         | **Description**                                                                  |
| ----------------- | ---------------------------- | -------------------------------------------------------------------------------- |
| `session_id`      | Stable across entire journey | Correlates all `/offers` calls belonging to a single customer flow.              |
| `id`              | New per `/offers` call       | Identifies a specific offer instance and keys the temporary stored quote record. |
| `offer_config_id` | Reused across sessions       | Identifies the underlying product rule configuration selected for display.       |

## Technical Integration

#### 1. Starting a New Session

Omit `partner.metadata.session_id` on your initial `create_offer` call (e.g., on the search or flight selection page). This signals the start of a new session.

```
POST /partners/{partner_code}/offers/
```

```json

{
  "schema": "travel_insurance_v1",
  "customer": {
    "currency": "USD",
    "language": "en",
    "country": "US"
  },
  "context": {
    "placement": "search",
    "trip_cost": 1200
  }
}
```

**Response (200 OK):**

Offers returns a newly generated `session_id` alongside the unique offer  `id` for this specific step.

```json
{
  "id": "off_01H123456789ABCDEF",
  "session_id": "sess_9876543210",
  "offer_config_id": "cfg_travel_standard",
  "currency": "USD",
  "products": [ ... ]
}
```

#### 2. Continuing an Existing Session

On subsequent steps (e.g., moving from search to checkout, or repricing at payment), include the `session_id` received from the previous response in `partner.metadata.session_id`.

```
POST /partners/{partner_code}/offers/
```

```json
{
  "schema": "travel_insurance_v1",
  "customer": {
    "currency": "USD",
    "language": "en",
    "country": "US"
  },
  "context": {
    "placement": "checkout",
    "trip_cost": 1200
  },
  "partner": {
    "metadata": {
      "session_id": "sess_9876543210"
    }
  }
}
```

**Response (200 OK):**

Offers echoes the exact same `session_id` back, while issuing a fresh offer `id` for the updated step.

```json
{
  "id": "off_02H987654321FEDCBA",
  "session_id": "sess_9876543210",
  "offer_config_id": "cfg_travel_standard",
  "currency": "USD",
  "products": [ ... ]
}
```

## End-to-End Journey Workflow

Below is a typical multi-step integration lifecycle:

<pre class="language-mermaid"><code class="lang-mermaid">---
config:
  theme: base
---
<strong>sequenceDiagram
</strong>    participant Customer as Customer
    participant Partner as Partner Backend
    participant Offers as Offers API

    %% Step 1: Search
    note over Customer, Offers: Step 1: Initial Offer (Search / Flight Selection)
    Customer->>Partner: Selects flight/search
    Partner->>Offers: POST /offers/ (no session_id)
    note over Offers: Generates new session_id (S1)&#x3C;br/>Runs selection logic -> offer id (O1)
    Offers-->>Partner: Returns offer id: O1, session_id: S1
    Partner-->>Customer: Displays offer O1

    %% Step 2: Checkout
    note over Customer, Offers: Step 2: Journey Continuation (Checkout)
    Customer->>Partner: Navigates to checkout
    Partner->>Offers: POST /offers/ (partner.metadata.session_id: S1)
    note over Offers: Uses session_id (S1)&#x3C;br/>Runs selection for checkout -> offer id (O2)
    Offers-->>Partner: Returns offer id: O2, session_id: S1
    Partner-->>Customer: Displays offer O2

    %% Step 3: Payment / Reprice
    note over Customer, Offers: Step 3: Reprice / Final Review
    Customer->>Partner: Proceeds to payment page
    Partner->>Offers: POST /offers/ (partner.metadata.session_id: S1)
    note over Offers: Uses session_id (S1)&#x3C;br/>Refreshes pricing for context -> offer id (O3)
    Offers-->>Partner: Returns offer id: O3, session_id: S1
    Partner-->>Customer: Displays final offer O3

    %% Step 4: Final Outcome (Confirm or Opt-Out)
    note over Customer, Offers: Step 4: Final Action (Purchase OR Decline)
    alt Customer Accepts Offer
        Customer->>Partner: Completes booking &#x26; pays for coverage
        Partner->>Offers: POST /offers/O3/confirm/
        Offers-->>Partner: Booking confirmed (Bound to session S1)
    else Customer Declines Offer
        Customer->>Partner: Completes booking without coverage
        Partner->>Offers: POST /offers/O3/opt_out/
        Offers-->>Partner: 204 No Content (Opt-out recorded for session S1)
    end

</code></pre>

1. Step 1 (Search): Request sent without `session_id`. Response returns `id: O1` and creates `session_id: S1`.
2. Step 2 (Checkout): Request includes `session_id: S1`. Response returns `id: O2` and echoes `session_id: S1`.
3. Step 3 (Payment / Reprice): Request includes `session_id: S1`. Context remains identical to Step 2, so Offers API returns the same offer refreshed with current pricing under a new `id: O3` and `session_id: S1`.
4. Step 4 (Final Action):
   * If Accepted: Call `POST /offers/O3/confirm/` using the latest offer `id`.
   * If Declined: Call `POST /offers/O3/opt_out/` using the latest `id`.

## Key Behaviors & Best Practices

#### Final Action Handling (Confirm vs. Opt-Out)

Just as you confirm the purchase using the latest offer `id` (`O3` in the flow above), when a customer actively declines coverage, call the Opt-Out endpoint using the most recent offer `id`. This ensures accurate conversion and attach-rate tracking for the session.

#### Partner-Supplied Session IDs

If you already maintain internal session tracking (e.g., a checkout session or cart ID), you may pass your own ID in `partner.metadata.session_id` on the first request. Offers API will adopt and preserve your supplied ID throughout the funnel.

> Integrity Requirement: When supplying your own IDs, ensure they are uniquely scoped per customer flow. Reusing a single ID across multiple distinct customers will merge separate user journeys into a single session in reporting.

#### Stateless Continuity

Passing `session_id` on request payloads allows Offers API to maintain stateless continuation. Every request triggers real-time offer evaluation and re-pricing against the provided context rather than serving stale, cached quotes.

#### Dynamic Offer Selection

Providing `session_id` does not force rotation or auto-exclude previously shown offers. Offers API continues using context-driven selection rules to return the optimal offer for each step.

* To explicitly suppress specific offer configurations across journey steps (e.g., preventing a previously shown offer from appearing again), continue using the standard `exclude_offer_ids` query parameter.

#### Boundary Handling

* Omitted Mid-Journey: If `session_id` is omitted on a subsequent call, Offers API interprets the request as a new boundary and generates a fresh `session_id`.
* Malformed or Unrecognized IDs: Offers API accepts provided IDs as valid session keys without strict database lookup validation; an unrecognized ID simply initializes a new tracked journey without throwing an API error.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://partner-docs.covergenius.com/offers/guides/multi-step-session-tracking.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
