# Enrich Transactions with Item-Level Data

Sail lets users connect their merchant accounts and retrieves their order history with product-level details. Instead of a flat transaction such as $49.00 at Walgreens, you can retrieve individual line items, such as bandages ($8.99), shampoo ($12.99), and a thermometer ($27.02).

In this guide, you'll create a user, connect a merchant account through Sail's connect widget, and pull back item-level expenses.

## Requirements

Before you start, make sure you have:

- A [Sail user](/docs/get-started/get-started-overview/create-a-user) created for your internal user
- An [API key](//docs/get-an-api-key) with the `expenses` scope
- A [webhook endpoint](/docs/get-started/get-started-overview/webhooks) configured to receive events

## Step 1: Connect a merchant account

To get [item-level data](/docs/concepts/transaction-level-and-item-level-expenses), your user needs to log into their merchant account. [Create a Connect Widget session](/reference/connect-account-widgets/post-hosted-sessions) with `connection_type` set to [`store`](/docs/concepts/account-connections). Sail returns a single-use URL that you embed in your app as an iframe or redirect. Your user enters their merchant credentials inside Sail's [Connect Account Widget](/docs/concepts/connect-widget), and those credentials never touch your servers.

<Tabs>
  <Tab title="Request">

  ```bash
  curl -X POST https://live.savewithsail.com/api/v1/hosted-sessions \
    -H "Authorization: Bearer sk_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "user_id": "usr_abc123",
      "flow": "connect_account",
      "options": {
        "connection_type": "store"
      }
    }'
  ```

  </Tab>
  <Tab title="Response">

  ```json
  {
    "url": "https://<HOSTED_SESSION_URL>",
    "expires_at": "2026-08-10T15:31:07Z",
    "flow": "connect_account"
  }
  ```

  </Tab>
</Tabs>

Open the `url` in an iframe or redirect your user to it. The session is single-use and the `expires_at` field tells you when it stops working. You can check which merchants Sail supports through the [List Merchants](/reference/merchants/get-merchants) endpoint.

## Step 2: Listen for webhooks

After your user completes the login, Sail syncs the merchant's order history. Listen for these webhook events to know when data is ready:

| Event | What it means |
| :--- | :--- |
| `connection.created` | Your user finished the connect widget and the connection exists. |
| `connection.status_changed` | The connection moved to a new status (for example, `aggregating` to `active`). |
| `connection.synced` | A sync finished. Check the `expenses_updated` flag to know if new expenses landed. |

When you receive `connection.synced` with `expenses_updated: true`, the data is ready to fetch.

<Callout type="info" title="Note">

The first connection sync pulls up to 15 months of order history from the merchant, not only new orders.

</Callout>

## Step 3: Pull item-level expenses

Once the sync completes, [fetch the user's expenses](/reference/expenses/get-users-user-id-expenses). Each item-level expense from a store connection represents a single product from an order.

<Tabs>
  <Tab title="Request">

  ```bash
  curl "https://live.savewithsail.com/api/v1/users/usr_abc123/expenses?source_type=store" \
    -H "Authorization: Bearer sk_live_..."
  ```

  </Tab>
  <Tab title="Response">

  ```json
  {
    "data": [
      {
        "id": "exp_9f2c",
        "connection_id": "conn_8e3a",
        "name": "Digital Thermometer",
        "description": "Digital Thermometer - Forehead",
        "date": "2026-08-05",
        "amount": 27.02,
        "status": "eligible",
        "source_type": "store",
        "origin": {
          "type": "product",
          "detail": "Digital Thermometer - Forehead"
        },
        "merchant": {
          "name": "Walgreens",
          "supported_merchant_id": "mer_walgreens"
        },
        "enrichment": {
          "category": "Pharmacies",
          "subcategory": "Drug Stores"
        },
        "parent_expense_id": null,
        "section_213d_classification": {
          "status": "eligible",
          "category": "Health Monitoring Devices",
          "reasoning": "Digital thermometers are eligible medical devices under Section 213(d)."
        }
      }
      // ... 2 more items (Bandages $8.99, Shampoo $12.99)
    ],
    "pagination": {
      "limit": 25,
      "offset": 0,
      "total": 3
    }
  }
  ```

  </Tab>
</Tabs>

Amounts are decimal numbers in USD (for example, `27.02` means $27.02).

Each item-level expense includes:

- **`source_type: "store"`** — it came from a merchant connection.
- **`origin.type: "product"`** — it's an individual product, not a flat transaction.
- **`enrichment`** — Sail adds a category and subcategory for each product.
- **`section_213d_classification`** — whether the expense qualifies as a tax-deductible healthcare expense under IRS Section 213(d).  To learn more about how classification works, see the [Classify your own transactions](/docs/guides/classify-your-own-transactions) guide.