# Overview

Source: https://gokarla.io/docs/platform/segments

# Segments

Segments are free-form string labels attached to an order. Karla uses them to
decide which [campaigns](/docs/guides/portal/campaigns) render on the tracking
page, and they can also gate shipment-handling rules. A single order can carry
any number of segments.

If you run a native shop integration (Shopify, Shopware) you mostly get
segments for free from order tags. If you build on the API directly, you send
them yourself on the order payload — that's what this page covers.

## Where segments come from

An order's segments are the **union of two sources**:

1. **Sent by you via the API** — the `segments` array on the order payload.
2. **Populated by Karla's shop integrations**, which send segments on the same
   order payload — the Shopify and Shopware apps both upsert orders, so their
   segments merge with yours rather than overwriting them:
   - **Shopify** — each order/customer tag becomes `Shopify.tag.<tag>`. See
     [Customer segments via order tags](/docs/guides/shops/shopify#customer-segments-via-order-tags).
   - **Shopware** — tags, customer group, and sales channel become
     `Shopware.tag.<tag>`, `Shopware.customer_group.<group>`, and
     `Shopware.sales_channel.<channel>`. See
     [Order segments](/docs/guides/shops/shopware#order-segments).
   - **Klaviyo** — list and segment membership become `Klaviyo.list.<name>`
     and `Klaviyo.segment.<name>` (looked up by customer email).

Both sources land in the same `segments` list on the order, so a campaign can
target a tag you set in Shopify and a segment you pushed via the API
interchangeably.

## Naming convention

Karla treats segments as opaque strings — it does not parse or validate them.
The dotted `Source.type.value` shape on integration segments
(`Shopify.tag.vip`, `Klaviyo.list.newsletter`) is just a convention.

Because your API-supplied segments share the same list as integration-derived
ones, the one thing to watch is **collisions** — pick values that won't
accidentally match a segment another connected service emits. Namespacing your
own (e.g. `tier.gold`, `erp.region.dach`) is an easy way to stay clear, but
it's optional. A couple of things to know either way:

- Segments are **case-sensitive** and stored verbatim — Karla applies no
  lowercasing, trimming, or deduplication of values. Integration segments show
  this too: a Shopware sales channel named `Storefront DE` becomes the segment
  `Shopware.sales_channel.Storefront DE`, spaces and all. `VIP` and `vip` are
  two different segments.
- There is no enforced length, count, or character limit — but keep them short
  and machine-readable; you'll be matching them exactly in campaign rules.
- **Don't put PII in segments.** They're labels for targeting, not a place for
  email addresses, names, or order contents.

## Sending segments via the API

`segments` is an optional `array<string>` on the order. The endpoint you call
decides whether the segments you send are **merged** with what Karla already
knows or **replace** the list entirely — that's the part to get right.

| Operation                 | Request                                    | `segments` lives          | Effect on existing segments                     |
| ------------------------- | ------------------------------------------ | ------------------------- | ----------------------------------------------- |
| **Upsert Order**          | `PUT /v1/shops/{slug}/orders`              | inside the `order` object | **Merged** — union with existing, deduplicated  |
| **Place Order**           | `POST /v1/shops/{slug}/orders`             | top level                 | **Merged** with Karla-derived segments          |
| **Fulfill Orders** (bulk) | `PUT /v1/shops/{slug}/orders/bulk`         | inside each `order`       | **Merged** — same as Upsert                     |
| **Update Order**          | `PATCH /v1/shops/{slug}/orders/{order_id}` | top level                 | **Replaced** — wholesale, drops everything else |

For the complete request and response shapes — required fields, address,
products, tracking — follow the matching operation in the
[API reference](/docs/api-reference). It's generated live from the OpenAPI
spec, so it never drifts from the real contract. All four operations
authenticate with HTTP Basic auth (`your-username:your-private-api-key`).

### Add segments — Upsert (recommended)

Upsert is the recommended write path: it's keyed by your `order_number` or
external id, so you don't need Karla's internal order id. The `segments` you
send (inside the `order` object) are unioned with whatever Karla already has,
including integration-derived ones — so it's the way to **add** labels without
disturbing the rest.

```jsonc
// PUT /v1/shops/{slug}/orders  — body fragment
{
  "id": "ORD-12345",
  "id_type": "order_number",
  "order": {
    "segments": ["tier.gold", "region.dach"]
    // …plus order_number, address, and the rest of the order fields
  }
}
```

If the order already had `Shopify.tag.vip`, after this call it carries
`Shopify.tag.vip`, `tier.gold`, and `region.dach`.

### Replace the list — Update Order

`PATCH` **replaces** the entire segment list with exactly what you send. Use it
to remove a segment or reset an order to a known set. Two things to note:

- The path takes the **Karla order id** — the UUID Karla assigns, not your
  `order_number`. You'll find it on the order's API record.
- Omitting `segments` from the request leaves the existing list untouched (the
  field is only applied when present).

:::warning Replace drops Karla-derived segments
A `PATCH` that sends `segments` overwrites the whole list. If the order had
`Shopify.tag.*` or `Klaviyo.*` segments, a `PATCH` that omits them removes
them. Send them back explicitly if you want to keep them, or use **Upsert** to
add segments without touching the rest.
:::

## Lifecycle

Segments are not frozen at order creation — Karla re-evaluates them as the
order moves through its lifecycle:

1. **At placement** — your API-supplied segments plus all integration sources
   are read.
2. **At every update** — re-read from the relevant source (e.g. Shopify order
   tags from the webhook payload).
3. **At fulfillment** — all sources are re-checked. This is the snapshot that
   decides which campaign the tracking page shows.

The campaign assignment is locked in at fulfillment and won't change
afterward, even if a customer's segments change later. For the full evaluation
timing — including the Klaviyo one-hour cache — see
[How segmentation works](/docs/guides/portal/campaigns#how-segmentation-works).

:::note Ordering is not guaranteed
The segment list is stored as an unordered set internally, so don't rely on
the order in which segments appear. When an order matches several campaigns,
Karla shows the first match it finds.
:::

## How segments are used

- **Campaign targeting** — segments select which banner and promotion
  campaigns render on the tracking page, falling back to the `default`
  campaign when nothing matches. See
  [Campaigns](/docs/guides/portal/campaigns).
- **Shipment rules** — segments can override whether specific shipments are
  submitted to carriers.

Because segments cleanly partition your customers, they're also a convenient
basis for A/B testing variations of your post-purchase experience.

## Related

- [Orders](/docs/platform/orders) — the entity that carries segments.
- [Campaigns](/docs/guides/portal/campaigns) — the main consumer of segments,
  with the full evaluation-timing and matching rules.
- [Shopify order tags](/docs/guides/shops/shopify#customer-segments-via-order-tags)
  and [Shopware order segments](/docs/guides/shops/shopware#order-segments) —
  integration-derived segments.
- [API reference](/docs/api-reference) — full request/response shapes for every
  order endpoint.
