# BreezeIQ integration guide Source: https://docs.breezeiq.in. Each section below is one page of the docs. --- Customer Data Platform # One customer, every touchpoint. BreezeIQ turns the events your apps already emit into a single, always-current profile per customer: who they are across devices, what they did, which audiences they belong to. You read it over a simple JSON API, or get a webhook the moment someone enters or leaves a segment. [Start the quickstart](https://docs.breezeiq.in/quickstart.md) Use with AI New here? The [Quickstart](https://docs.breezeiq.in/quickstart.md) takes you to your first profile, metric and segment in about 15 minutes. Every control-plane endpoint, with requests and responses, is in the [API reference](https://docs.breezeiq.in/api.md). ## Start by goal - [Send events](https://docs.breezeiq.in/server-events.md): Send orders, logins and other trusted events from your backend. - [Build audiences](https://docs.breezeiq.in/segments.md): Describe an audience as a rule over metrics. - [Read customer data](https://docs.breezeiq.in/api/profiles.md): Look up any customer by email or phone, with metrics and segments. - [Recipes](https://docs.breezeiq.in/use-cases.md): VIPs, win-back, abandoned checkout and more, ready to paste. ## How it works You send events. BreezeIQ derives everything else from them. | Stage | What happens | | --- | --- | | [Events](https://docs.breezeiq.in/events.md) | Your apps send events carrying identifiers and properties. | | [Identity](https://docs.breezeiq.in/profiles.md) | Each event resolves to one profile per person. | | [Metrics](https://docs.breezeiq.in/metrics.md) | Each event updates the metrics defined for it. | | [Segments](https://docs.breezeiq.in/segments.md) | Changed metrics re-check the segments that use them. | | [Read](https://docs.breezeiq.in/api.md) / [webhooks](https://docs.breezeiq.in/webhooks.md) | Query profiles and memberships, or receive entries and exits. | See [Concepts](https://docs.breezeiq.in/concepts.md) for the full flow and the terms every page uses. ## What you get - **Unified profiles**: Emails, phones, cookies and device ids are stitched into one profile. A visitor's browsing history joins their customer profile the moment they log in. - **Real-time metrics**: Define metrics like `total_spend`, `last_order_at`, `country` or `recent_cart_adds` once. They update within seconds of each event. - **Segments**: Describe an audience as a rule over metrics ("spent ₹10k+ and ordered in the last 30 days"). Membership is kept current automatically, including rules based on time. - **Webhooks & API**: Get a webhook on every segment entry or exit. Look up any customer by email or phone, or check a single membership in one call. ## Next - [Quickstart](https://docs.breezeiq.in/quickstart.md): First profile, metric and segment in about 15 minutes. - [Your values](https://docs.breezeiq.in/values.md): Set your tenant, workspace and URLs once for every example. --- # Quickstart Send your first event and see a profile, a metric and a segment in about 15 minutes. You register an event type, define three metrics, send one purchase, then look the customer up and put them in a segment. ## Before you begin Ask the BreezeIQ team for: | What | Used for | | --- | --- | | A **workspace** | Your store or brand | | The **collector token** | Sending server-side events | | A **control-plane token** | `cpt_...` to configure, or `cpw_...` for read-only access to one workspace. This quickstart writes configuration, so use a `cpt_...` token. | Enter them on [Your values](https://docs.breezeiq.in/values.md) and every example on this page updates to match. [Authentication](https://docs.breezeiq.in/authentication.md) covers the base URLs and tokens. ## Steps ### Step 1: Register your event types Every event name must be registered before it is accepted. Here, `purchase` is deduplicated on its order id. Request: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/event-types/purchase" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"dedup_entity": "order", "dedup_key_paths": ["properties.order_id"]}' ``` 200 OK: ```json { "tenant_id": "breeze", "event_name": "purchase", "status": "upserted" } ``` **Expected:** The response has `"status": "upserted"`. BreezeIQ accepts a new event type within a few minutes. ### Step 2: Define the metrics you care about Create three metrics fed by `purchase`, one request each. total_spend: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"metric_name":"total_spend","event_name":"purchase","value_kind":"property_number","value_path":"properties.amount","display_name":"Total spend"}' ``` order_count: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"metric_name":"order_count","event_name":"purchase","value_kind":"count","display_name":"Orders"}' ``` last_order_at: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"metric_name":"last_order_at","event_name":"purchase","value_kind":"occurred_at_epoch","display_name":"Last order"}' ``` > **Define metrics before you send:** Metrics count events received *after* they are defined, so define them before you start sending. **Expected:** Each response has `"status": "created"`. A metric definition takes effect within about a minute. ### Step 3: Send an event Send a server-side purchase to the collector. Server-side purchase: ```bash curl -X POST "https:///v1/events/authenticated" \ -H "Authorization: Bearer $COLLECTOR_TOKEN" \ -H "x-tenant-id: breeze" -H "x-workspace-id: my-store" \ -H "Content-Type: application/json" \ --data-binary '{"envelop_version":"1.0","id":"0b6bd7e7-1a4b-4d12-8fd3-9f8f0f2a1b2c","name":"purchase","tenant_id":"breeze","workspace_id":"my-store","anon_id":"cookie:3f9a1c7e","occured_at":"2026-10-08T10:15:00Z","properties":{"order_id":"ORD-10421","amount":2499,"currency":"INR","identifiers":{"email":"priya@example.com","phone":"+919812345678","cookie":"3f9a1c7e"}}}' ``` The body stays on one line: the collector reads one event per line. See [From your server](https://docs.breezeiq.in/server-events.md). **Expected:** The response counts the events: `"collected": 1`, `"filtered": 0` and `"total": 1`. If `filtered` is not 0, the collector doesn't allow the event name yet; ask the BreezeIQ team. ### Step 4: Look the customer up Find the profile by email. Find the profile by email: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/profiles/lookup?type=email&value=priya@example.com" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` **Expected:** You get the profile with its identifiers, metrics (`total_spend = 2499`, `order_count = 1`) and segments, usually within a few seconds of sending. ### Step 5: Create a segment Customers who spent 10,000 or more. Request: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments/vip-customers" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"workspace_id":"my-store","display_name":"VIP customers", "predicate":{"metric":"total_spend","op":"gte","value":10000}}' ``` 200 OK: ```json { "tenant_id": "breeze", "segment_id": "vip-customers", "is_temporal": false, "status": "created" } ``` **Expected:** Existing customers are evaluated right away. From then on, membership updates as events arrive, and entries and exits are sent to your [webhook](https://docs.breezeiq.in/webhooks.md). ## Next - [Webhooks](https://docs.breezeiq.in/webhooks.md): Get a POST when a customer enters or leaves a segment. - [Recipes](https://docs.breezeiq.in/use-cases.md): VIPs, win-back, abandoned checkout and more. - [API reference](https://docs.breezeiq.in/api.md): Every control-plane endpoint, with requests and responses. --- # Concepts How data flows through BreezeIQ, and the handful of terms every other page uses. Data flows one way, from your systems into profiles. You never write profiles directly: you send **events**, and BreezeIQ derives everything else from them. ## Components From left to right, the systems an event passes through: | Component | Role | | --- | --- | | **Your systems** | Website, app, order service, checkout | | **Events collector** | HTTPS endpoint that accepts events (browser or server) | | **BreezeIQ** | Resolves identity, folds metrics, evaluates segments ProfilesMetricsSegments | | **Control-plane API** | Out: profiles, lookups, segment members | | **Webhooks** | Out: segment entered / exited | ## Data flow 1. **Event in.** You send events (`purchase`, `addshippinginfo`, …) carrying the customer's identifiers (email, phone, cookie, device id) and properties (amount, product id, …). 2. **Identity.** BreezeIQ finds the profile those identifiers belong to, creates a new one, or merges two profiles when an event proves they are the same person. 3. **Metrics.** Each event updates the metrics defined for it: totals, counts, last-seen times, latest values, recent-item lists. 4. **Segments.** When a customer's metrics change, every segment that uses those metrics is re-checked. Entries and exits are recorded and sent as webhooks. 5. **Read.** Your apps query profiles and memberships through the control-plane API at any time. > **Everything is per workspace:** A *tenant* (for example `breeze`) owns configuration such as event types and metric definitions. Each *workspace* (one store or brand) has its own profiles, segments and members. Identities never cross workspaces. ## Glossary | Term | Meaning | | --- | --- | | [Tenant](https://docs.breezeiq.in/api/workspaces.md) | Owns configuration, such as event types and metric definitions, and its workspaces. For example `breeze`. | | [Workspace](https://docs.breezeiq.in/api/workspaces.md) | One store or brand in a tenant, with its own profiles, segments and members. Tenant-wide event types and metrics apply to it automatically. | | [Workspace alias](https://docs.breezeiq.in/api/workspaces.md) | Another name events may use for a workspace, such as a shop domain. Events sent with the alias are stored under the workspace. | | [Event](https://docs.breezeiq.in/events.md) | One JSON object describing one thing that happened. Browser and server events use the same format. | | [Event type](https://docs.breezeiq.in/api/event-types.md) | A registered, lowercase event name, such as `purchase`. Registration also decides how events of that type are deduplicated. | | [Identifier](https://docs.breezeiq.in/identifiers.md) | A value that says who an event is about. **Strong** identifiers (`email`, `phone`) name a person; **weak** ones (`cookie`, `device_id`) name a device, which may be shared. | | [Profile](https://docs.breezeiq.in/profiles.md) | One person in one workspace, plus every identifier seen for them. A **customer** has an email or phone; a **visitor** only has cookies or device ids. | | [Metric definition](https://docs.breezeiq.in/api/metric-definitions.md) | Also called a *claim*: "metric M is fed by event E, reading the value at path P". One metric can have a claim per event. | | [Metric](https://docs.breezeiq.in/metrics.md) | A value kept per customer and updated by events, such as `total_spend` or `last_order_at`. | | [Segment](https://docs.breezeiq.in/segments.md) | A rule over metrics; each customer is either in or out. A **temporal** segment uses `within_days` / `beyond_days`, is re-checked periodically, and is marked `"is_temporal": true`. | | [Membership and transitions](https://docs.breezeiq.in/webhooks.md) | Membership is one customer's in/out status in a segment. A transition is a change: `entered` or `exited`, with an `origin` (`live-eval`, `backfill` or `merge-remap`) saying why. | | [Webhook](https://docs.breezeiq.in/webhooks.md) | A POST to your endpoint when a customer enters or leaves a segment. | | [Events collector](https://docs.breezeiq.in/server-events.md) | The HTTPS service that accepts events, from the browser or your servers. | | [Control plane](https://docs.breezeiq.in/api.md) | The API for configuration (event types, metrics, segments) and reads (profiles, members). | | [Tenant token](https://docs.breezeiq.in/authentication.md#control-plane-tokens) | `cpt_...`. Can do everything in the tenant. Issued by the BreezeIQ team. | | [Workspace token](https://docs.breezeiq.in/api/tokens.md) | `cpw_...`. Read-only access to one workspace. Minted with a tenant token. | ## Next - [Quickstart](https://docs.breezeiq.in/quickstart.md): See the whole flow end to end in about 15 minutes. - [Event format](https://docs.breezeiq.in/events.md): The fields every event carries. --- # Authentication The two services you call, their base URLs, and the tokens each one takes. ## Services and base URLs There are two services you talk to: | Service | Used for | Base URL | | --- | --- | --- | | **Events collector** | Sending events, from the browser or your servers | `https:///v1` | | **Control plane** | Configuration (event types, metrics, segments) and reads (profiles, members) | `https://api.breeze.in/cdp/control-plane` | Set your own base URLs, tenant and workspace on [Your values](https://docs.breezeiq.in/values.md), and every example on the site uses them. ## Collector authentication | Events | Endpoint | Token | Identifiers accepted | | --- | --- | --- | --- | | [Server-side](https://docs.breezeiq.in/server-events.md) | `/events/authenticated` | `Authorization: Bearer $COLLECTOR_TOKEN` | All, including email and phone. These events are trusted and can link identities. | | [Browser](https://docs.breezeiq.in/browser-events.md) | `/events` | None | Device-level only (`cookie`, `device_id`), because anyone can call it. | ## Control-plane tokens Every request carries `Authorization: Bearer `. There are two kinds of token: | Token | Format | Who has it | Can do | | --- | --- | --- | --- | | **Tenant** | `cpt_.` | Your platform or admin service (issued by the BreezeIQ team) | Everything in the tenant: configuration writes, all workspaces, minting workspace tokens | | **Workspace** | `cpw_.` | Dashboards and apps of one workspace | Read-only: that workspace's profiles, segments and members, plus the tenant's event types and metric definitions | A token can never see another tenant's data, and a workspace token can never see another workspace's data (`403`). Mint workspace tokens with the [Tokens API](https://docs.breezeiq.in/api/tokens.md). ### Check a token `GET /v1/whoami` · tenant or workspace token Returns what the token is for. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/whoami" -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` Workspace token: ```json { "scope": "workspace", "tenant_id": "breeze", "workspace_id": "my-store" } ``` Tenant token: ```json { "scope": "tenant", "tenant_id": "breeze" } ``` > **Keep tokens in environment variables:** Use environment variables (`export BREEZEIQ_TOKEN=...`) rather than pasting tokens into scripts or tickets. Every example here uses them that way. ## Next - [Quickstart](https://docs.breezeiq.in/quickstart.md): Use your tokens to send a first event. - [Tokens API](https://docs.breezeiq.in/api/tokens.md): Mint, list and revoke workspace tokens. --- # Your values Set your tenant, workspace and URLs once, and every example on the site uses them. Every code sample on the site is written with these four values. Change them here and the examples, Copy page and the AI panel all use yours. ## What each value is | Value | What it is | Example default | | --- | --- | --- | | Tenant | Owns your configuration: event types and metric definitions. Sent as `tenant_id` and `x-tenant-id`. | `breeze` | | Workspace | One store or brand, with its own profiles, segments and members. Sent as `workspace_id` and `x-workspace-id`. | `my-store` | | Control-plane base URL | Configuration and reads. See [API reference](https://docs.breezeiq.in/api.md). | `https://api.breeze.in/cdp/control-plane` | | Collector base URL | Where events are sent. See [From your server](https://docs.breezeiq.in/server-events.md). | `https:///v1` | > **Tokens stay out of the page:** Tokens are never asked for here. Examples read them from `$BREEZEIQ_TOKEN` and `$COLLECTOR_TOKEN`; keep them in environment variables (`export BREEZEIQ_TOKEN=...`) rather than pasting them into scripts or tickets. ## Next - [Authentication](https://docs.breezeiq.in/authentication.md): Base URLs and the tokens each service takes. - [Quickstart](https://docs.breezeiq.in/quickstart.md): Send your first event with these values. --- # Event format The event envelope: required fields, exact spellings, properties and timestamps. An event is one JSON object describing one thing that happened. Browser and server events use the same format. ## Example purchase event: ```json { "envelop_version": "1.0", "id": "0b6bd7e7-1a4b-4d12-8fd3-9f8f0f2a1b2c", "name": "purchase", "tenant_id": "breeze", "workspace_id": "my-store", "anon_id": "cookie:3f9a1c7e", "occured_at": "2026-10-08T10:15:00Z", "properties": { "order_id": "ORD-10421", "amount": 2499, "currency": "INR", "identifiers": { "email": "priya@example.com", "phone": "+919812345678", "cookie": "3f9a1c7e" } } } ``` > **Two fields are spelled on purpose:** `envelop_version` (one "e") and `occured_at` (one "r") are spelled exactly like that. Events with the "correct" spellings are rejected. ## Fields - `envelop_version` (string, required): Always `"1.0"`. The spelling (one "e") is part of the format. - `id` (string (UUID), required): Unique event id. Resending the same id is safe: it is processed once. - `name` (string, required): Event type, lowercase, and [registered](https://docs.breezeiq.in/api/event-types.md) beforehand, such as `purchase`, `initiatecheckout` or `addshippinginfo`. - `tenant_id` (string, required): Your tenant. Matches the `x-tenant-id` header. - `workspace_id` (string): Your workspace id or one of its aliases, such as a shop domain. **Always send it**: when it's missing, the event goes to a workspace named `default`. - `anon_id` (string, required): A stable id for the sender, usually the browser cookie. In the typed form `"cookie:"` it also counts as an identifier when `properties.identifiers` is absent. - `actor_id` (string): Typed identifier of a known user, such as `"email:priya@example.com"`. Only used when `properties.identifiers` is absent. - `occured_at` (RFC 3339 time, required): When it happened, in UTC, such as `2026-10-08T10:15:00Z`. Spelled with one "r". Metrics and "last seen" times use this, not the arrival time. - `properties` (object): Anything about the event: amount, order id, product id, country. Metrics read values from here by path. - `properties.identifiers` (object): **Who this is**: a map of identifier type to value(s). See [Identifiers](https://docs.breezeiq.in/identifiers.md). It is removed from the stored properties. ## Next - [Identifiers](https://docs.breezeiq.in/identifiers.md): Tell BreezeIQ who each event belongs to. - [From your server](https://docs.breezeiq.in/server-events.md): Send trusted events with email and phone. - [From the browser](https://docs.breezeiq.in/browser-events.md): Send anonymous events from your storefront. --- # Identifiers Tell BreezeIQ who an event is about: email, phone, cookie and device id. Identifiers are how BreezeIQ knows two events belong to the same person. Put every identifier you know in `properties.identifiers`: the more you send, the better events stitch together. ## Identifier types Strong identifiers name a person. Weak ones name a device, which may be shared. | Type | Strength | How it's matched | | --- | --- | --- | | `email` | Strong | Trimmed and lowercased, so `Priya@Example.com` equals `priya@example.com`. | | `phone` | Strong | Normalised to E.164. Numbers without a country code are treated as Indian (`9812345678` → `+919812345678`). | | `cookie` | Weak | Browser cookie id. Allowed from browser events. | | `device_id` | Weak | App or device id. Allowed from browser events. | A shared device can never glue two known customers together. See [Profiles & identity](https://docs.breezeiq.in/profiles.md) for how matching and merging work. ## Sending identifiers Each type takes a single value, a list, or objects with a `value`: Accepted value forms: ```json "identifiers": { "email": "priya@example.com", // a single value "phone": ["+919812345678", "+919900112233"], // several values "cookie": [{ "value": "3f9a1c7e" }], // object form "device_id": "a1b2c3d4-e5f6-4711-9c2d-1f2e3d4c5b6a" } ``` ## Rules | Rule | What happens | | --- | --- | | Only declared types count | Each tenant has a list of identifier types. Unknown types in an event are ignored; if nothing usable is left, the event is rejected. | | At most 10 values | Per event, across all types. | | Placeholders are ignored | Values configured as "noise" (such as `test@example.com`) never link anyone. Ask the BreezeIQ team to add yours. | > **Identifiers are protected:** Identifier values are encrypted at rest and never appear in webhooks. See [Data & privacy](https://docs.breezeiq.in/privacy.md). ## Next - [From your server](https://docs.breezeiq.in/server-events.md): Send email and phone with trusted events. - [From the browser](https://docs.breezeiq.in/browser-events.md): Anonymous events with cookie and device id. --- # From your server Trusted events from your backend, which can carry email and phone and link profiles. Use server-side events for anything your backend knows for sure: orders, payments, shipping details, logins. These events are **trusted**. They can carry email and phone, and when one event shows that two existing profiles are the same person, those profiles are merged. ### Send server events `POST https:///v1/events/authenticated` · collector token **Headers** - `Authorization` (string, required): `Bearer $COLLECTOR_TOKEN` - `x-tenant-id` (string, required): Your tenant. - `x-workspace-id` (string): Your workspace. - `Content-Type` (string): `application/json` The body is newline-delimited JSON: one [event](https://docs.breezeiq.in/events.md) per line, so you can send several events in one request. Keep each event on a single line; that's why the events below aren't pretty-printed. Request: ```bash curl -X POST "https:///v1/events/authenticated" \ -H "Authorization: Bearer $COLLECTOR_TOKEN" \ -H "x-tenant-id: breeze" -H "x-workspace-id: my-store" \ -H "Content-Type: application/json" \ --data-binary @- <<'EOF' {"envelop_version":"1.0","id":"7c1e7a52-6f0e-4c0c-9a8b-2d4e6f8a0b1c","name":"addshippinginfo","tenant_id":"breeze","workspace_id":"my-store","anon_id":"cookie:3f9a1c7e","occured_at":"2026-10-08T10:14:12Z","properties":{"checkout_id":"CHK-88","country":"IN","identifiers":{"email":"priya@example.com","cookie":"3f9a1c7e"}}} {"envelop_version":"1.0","id":"0b6bd7e7-1a4b-4d12-8fd3-9f8f0f2a1b2c","name":"purchase","tenant_id":"breeze","workspace_id":"my-store","anon_id":"cookie:3f9a1c7e","occured_at":"2026-10-08T10:15:00Z","properties":{"order_id":"ORD-10421","amount":2499,"currency":"INR","identifiers":{"email":"priya@example.com","phone":"+919812345678"}}} EOF ``` 200 OK: ```json { "filtered": 0, "collected": 2, "total": 2 } ``` **Response** - `collected` (number): Events accepted for processing. - `filtered` (number): Events whose name isn't allowed by the collector's configuration. - `total` (number): Events in the request. ## Next - [Delivery & retries](https://docs.breezeiq.in/delivery.md): Status codes, retries and how duplicates are handled. - [Identifiers](https://docs.breezeiq.in/identifiers.md): Which identifiers to send and how they match. - [From the browser](https://docs.breezeiq.in/browser-events.md): Anonymous events from your storefront. --- # From the browser Anonymous storefront events with no token, sent one by one or in batches. Use browser events for things that happen before anyone logs in: page views, product views, cart adds. The endpoint needs no token, so storefront code can call it directly. ### Send a browser event `POST https:///v1/events` · No token The body is one [event](https://docs.breezeiq.in/events.md). From your storefront: ```js await fetch("https:///v1/events", { method: "POST", headers: { "content-type": "application/json", "x-tenant-id": "breeze", "x-workspace-id": "my-store" }, body: JSON.stringify({ envelop_version: "1.0", id: crypto.randomUUID(), name: "addtocart", tenant_id: "breeze", workspace_id: "my-store", anon_id: "cookie:" + visitorId, occured_at: new Date().toISOString(), properties: { product_id: "SKU-1042", price: 1399, identifiers: { cookie: visitorId } } }) }); ``` Cross-origin calls need CORS enabled on the collector for your domain. The BreezeIQ team sets that up. ## Untrusted by design Anyone could claim an email or phone from a browser, so BreezeIQ limits what browser events can do: - Only `cookie` and `device_id` are kept. Email and phone are dropped. - Browser events never merge two existing profiles. > **Anonymous activity still counts:** When the same cookie later appears in a [server-side event](https://docs.breezeiq.in/server-events.md) together with an email (login, order), the visitor's history joins that customer's profile. ## Batches To send several events as one JSON document instead of one per line, use the batch endpoint. It takes the same events, without a token. ### Send a batch `POST https:///v1/events/batch` · No token The body is an object whose `events` array holds the events. Request body: ```json { "events": [ { "envelop_version": "1.0", "id": "1f7c…", "name": "addtocart", "tenant_id": "breeze", "workspace_id": "my-store", "anon_id": "cookie:3f9a1c7e", "occured_at": "2026-10-08T10:11:02Z", "properties": { "product_id": "SKU-1042", "identifiers": { "cookie": "3f9a1c7e" } } } ] } ``` Batch events count as browser events: device-level identifiers only. ## Next - [From your server](https://docs.breezeiq.in/server-events.md): Trusted events that link anonymous visitors to customers. - [Delivery & retries](https://docs.breezeiq.in/delivery.md): Status codes, retries and how duplicates are handled. --- # Delivery & retries What a 200 means, when to retry, and how duplicates and late events are handled. ## How delivery works - **Asynchronous.** A `200` means the event was queued. Profiles and metrics update a few seconds later. An event that fails validation afterwards, such as one with an unregistered name, is set aside and does not appear on any profile. - **Safe to retry.** Retry on timeouts and `5xx`. Each event is processed once: by its `id`, or by the event type's business key (such as `order_id`) when one is configured. - **Event time wins.** Late events are placed by `occured_at`. A delayed old event never overwrites a newer "latest" value or reorders recent lists. - **Business-key dedup.** With `dedup_key_paths: ["properties.order_id"]`, two `purchase` events for the same order count once, even with different ids. Configure it when you [register the event type](https://docs.breezeiq.in/api/event-types.md#register-an-event-type). ## Status codes | Status | Meaning | What to do | | --- | --- | --- | | `200` | Queued | Nothing to do. | | `400` | Invalid JSON, missing `x-tenant-id`, or a body that isn't UTF-8 | Fix the request. Don't retry it as is. | | `401` | Missing or wrong token on `/events/authenticated` | Check `$COLLECTOR_TOKEN`. | | `500` / `502` / `503` | Temporary failure | Retry with backoff. Duplicates are harmless. | ## Next - [Event types](https://docs.breezeiq.in/api/event-types.md): Register event names and their business keys. - [Troubleshooting](https://docs.breezeiq.in/troubleshooting.md): Events that don’t show up where you expect. - [Profiles & identity](https://docs.breezeiq.in/profiles.md): What your events build. --- # Profiles & identity How events become profiles, when profiles merge, and the rules that keep merges safe. A **profile** is one person in one workspace, plus every identifier seen for them. Profiles are what metrics are kept on and what segments count, so getting identity right is what makes your audiences correct. ## How events find a profile Each event resolves to a profile in one of three ways: | Outcome | When | What happens | | --- | --- | --- | | New | No identifier in the event is known yet. | A new profile is created. | | Extend | A known identifier arrives with new ones. | The new identifiers join that profile. Example: a phone number seen for the first time with a known email. | | Merge | A trusted event shows two profiles are the same person. | The profiles merge. Their history and metrics are combined and recalculated. | ## Customers and visitors Every profile has a `profile_type`: | `profile_type` | Has | | --- | --- | | `customer` | An email or phone. | | `visitor` | Only cookies or device ids. | A visitor becomes a customer automatically once an email or phone is attached, typically at login or checkout. List endpoints accept `?profile_type=customer` or `?profile_type=visitor`. See [Profiles API](https://docs.breezeiq.in/api/profiles.md) and [Segment members](https://docs.breezeiq.in/api/segment-members.md). ## Safety rules | Rule | What happens | | --- | --- | | Shared devices don't glue customers together | If a family laptop's cookie has been used by two customers with different emails, the cookie alone never merges them. | | Browser events never merge | A browser event never merges two existing profiles. Only server-side events can. | | Placeholders are ignored | Identifiers configured as noise values are ignored entirely. | | Merged-away ids keep resolving | API lookups by an old, merged-away profile id return the surviving profile. | > **Merge from your server:** Since only server-side events can merge profiles, send the event that links a login or order to an email or phone from your backend. See [From your server](https://docs.breezeiq.in/server-events.md). ## Next - [Metrics](https://docs.breezeiq.in/metrics.md): Values kept per customer, updated by events. - [Identifiers](https://docs.breezeiq.in/identifiers.md): Which identifiers to send and how they match. --- # Metrics Per-customer values kept current by events: counts, totals, last-seen times, latest values and lists. A metric is a value kept per customer and updated by events, such as `total_spend` or `last_order_at`. Metrics are what segments are built on: decide what you want to target, then define the metrics that measure it. You define a metric once as a **metric definition** (also called a *claim*): "metric M is fed by event E, reading the value at path P". BreezeIQ then keeps it current for every customer. To create and list definitions, see the [Metric definitions API](https://docs.breezeiq.in/api/metric-definitions.md). ## Value kinds | `value_kind` | What the metric holds | Example | | --- | --- | --- | | `count` | Number of events | `order_count` on `purchase` | | `property_number` | Sum of a number in the event, read at `value_path` | `total_spend` = sum of `properties.amount` | | `occurred_at_epoch` | Time of the most recent event (Unix seconds) | `last_order_at`, `last_checkout_at` | | `property_string` + `"aggregation": "latest"` | The newest text value (newest by event time) | `country`, `last_payment_method` | | `property_string` + `"aggregation": "recent"` | The newest `keep` distinct values, newest first (`keep` 1–10, default 5) | `recent_cart_adds` = the last 5 products added | ## Rolling windows Limit `count` and `property_number` to a rolling window with `window_days` (1–730), for example `spend_last_30d`. The value goes down by itself as old events fall out of the window. ## Value paths `value_path` is a dotted path from the event root, starting with `properties.`. For this event, `properties.amount` reads `2499` and `properties.shipping.country` reads `"IN"`. Reading values by path: ```json { "name": "purchase", "properties": { "amount": 2499, "shipping": { "country": "IN" } } } ``` ## Text and list metrics - Text values are trimmed and capped at 128 characters. Numbers and true/false become text. Empty values, objects and arrays are skipped. - On a profile, a `latest` metric carries `"text"` and a `recent` metric carries `"items"`, each item with the time it was last seen. - Their numeric `value` is the time of the newest value. How text and list metrics appear on a profile: ```json "metrics": [ { "metric": "total_spend", "display_name": "Total spend", "value": "4998", "stamped_version": 3 }, { "metric": "country", "display_name": "Country", "value": "1791364450", "text": "IN", "stamped_version": 3 }, { "metric": "recent_cart_adds", "display_name": "Recent cart adds", "value": "1791370287", "stamped_version": 3, "items": [ { "value": "SKU-7", "at": "2026-10-07T10:51:27Z" }, { "value": "SKU-6", "at": "2026-10-07T10:51:22Z" }, { "value": "SKU-5", "at": "2026-10-07T09:14:30Z" } ] } ] ``` ### In segments Because `value` is a time, segments can ask "added to cart in the last day" (`within_days`) or whether the metric exists at all. Matching on the text itself (for example `country = "IN"`) isn't supported in segments yet; read it from the profile instead. ## Rules > **Metrics are forward-only:** A new metric counts events received after it is defined; history isn't backfilled. To include older activity, resend those events with their original `occured_at`. Deduplication keeps events that were already counted from counting twice. > **Definitions can't be edited:** To change one, delete it and create it again, or use a new metric name, so existing totals never silently change meaning. ## One metric, several events To feed one metric from several events, create one metric definition per event with the same `metric_name`. For example, `last_seen_at` fed by both `purchase` and `initiatecheckout`. ## Next - [Segments](https://docs.breezeiq.in/segments.md): Turn metrics into audiences with rules. - [Metric definitions API](https://docs.breezeiq.in/api/metric-definitions.md): Create, list and delete definitions. - [Use-case recipes](https://docs.breezeiq.in/use-cases.md): Ready-made metrics and segments. --- # Segments Audiences defined as rules over metrics, re-evaluated automatically as customers change. A segment is a rule over [metrics](https://docs.breezeiq.in/metrics.md) that defines an audience. Each customer is either **in** or **out**, and BreezeIQ re-checks them whenever a metric the rule uses changes, so the audience stays current without any batch job. ## Rules A rule is a JSON tree of `all` / `any` / `not` groups over metric conditions. Big spenders, active recently, not refund-heavy: ```json { "all": [ { "metric": "total_spend", "op": "gte", "value": 10000 }, { "any": [ { "metric": "order_count", "op": "gte", "value": 3 }, { "metric": "last_order_at", "op": "within_days", "value": 30 } ] }, { "not": { "metric": "refund_count", "op": "gt", "value": 2 } } ] } ``` ## Operators | `op` | `value` | True when | Works on | | --- | --- | --- | --- | | `eq` `neq` `gt` `gte` `lt` `lte` | number | The comparison holds (exact decimals, safe for money) | Number metrics | | `between` | `[lo, hi]` | `lo ≤ metric ≤ hi`, inclusive at both ends | Number metrics | | `exists` / `missing` | none | The customer has / doesn't have this metric | All metrics | | `within_days` | whole days | Happened in the last N days | Time metrics, text and list metrics | | `beyond_days` | whole days | Last happened more than N days ago | Time metrics, text and list metrics | ## Missing metrics A condition on a metric the customer doesn't have is **false**, except `missing`, which is true. > **"Churned" excludes people who never ordered:** `last_order_at beyond_days 90` does *not* include people who never ordered. To target them, say it explicitly: `{"metric": "last_order_at", "op": "missing"}`. ## Time-based rules Rules using `within_days` or `beyond_days` change with time alone. BreezeIQ re-checks them periodically, so people age in and out without any new event. The API marks these segments `"is_temporal": true`. ## Lifecycle | Stage | What happens | | --- | --- | | Writing a rule | Use [preview](https://docs.breezeiq.in/api/segments.md): it validates the rule and counts matches without saving anything. | | Creation | Every existing customer is evaluated once (a "backfill"), so the segment is accurate from the start. | | After creation | Rules are fixed. To change one, create a new segment id. Only `status` can change. | Status values: draft active paused archived ## Next - [Webhooks](https://docs.breezeiq.in/webhooks.md): Get a POST when customers enter or leave. - [Segments API](https://docs.breezeiq.in/api/segments.md): Create, preview and manage segments. - [Use-case recipes](https://docs.breezeiq.in/use-cases.md): Ready-made segments to copy. --- # Webhooks Get notified when a customer enters or leaves a segment. Every time a customer enters or leaves a [segment](https://docs.breezeiq.in/segments.md), BreezeIQ can POST it to your endpoint. Use webhooks to send reminders or tag customers in your CRM the moment they qualify. ## Choose what is sent Each segment's `automations` decide which changes are sent. **automations** - `on_enter` (boolean): Send entries. Default `true`. - `on_exit` (boolean): Send exits. Default `true`. - `on_backfill` (boolean): Also send changes from the initial backfill and periodic time-based re-checks. Default `false`, so creating a segment doesn't flood you. ## Payload POST to your webhook URL: ```json { "idempotency_key": "4b1f0c2d9e8a7b6c5d4e3f2a1b0c9d8e", "tenant_id": "breeze", "workspace_id": "my-store", "segment_id": "vip-customers", "profile_id": "60de1d6e-748f-87dc-ab33-bfbbaba9b299", "transition": "entered", "origin": "live-eval", "evaluated_version": 3, "occurred_at": "2026-10-08T10:15:04Z" } ``` **Fields** - `transition` (string): `entered` or `exited`. - `origin` (string): Why it changed: - `live-eval`: an event changed a metric. - `backfill`: segment creation or a time-based re-check. - `merge-remap`: two profiles merged. - `profile_id` (string): Who. Fetch details with `GET .../profiles/{profile_id}` ([Profiles API](https://docs.breezeiq.in/api/profiles.md)). - `idempotency_key` (string): Stable per change. Use it to drop duplicate deliveries. ## Delivery | Rule | What it means for you | | --- | --- | | At-least-once delivery | Any `2xx` counts as delivered; anything else is retried until it succeeds. Deduplicate on `idempotency_key`. | | No personal data | Webhooks carry ids only. Call the profile API for emails, phones and metrics. | | URL set by the BreezeIQ team | The webhook URL is set per environment. Send the BreezeIQ team your endpoint. | | Routing | Route on `workspace_id` and `segment_id`. | > **Prefer polling?:** Use [segment members](https://docs.breezeiq.in/api/segment-members.md) or the single-customer membership check instead of webhooks. ## Next - [Use-case recipes](https://docs.breezeiq.in/use-cases.md): Segments and webhooks put to work. - [Segment members API](https://docs.breezeiq.in/api/segment-members.md): List members or check one customer. --- # Recipes Complete setups for common goals: VIPs, win-back, abandoned checkout and more. Complete, copy-pasteable setups built on the events you already send. Each recipe lists what it's for, the event and metrics it needs, the setup, and how to use the result. - [High-value customers](#uc-vip): Spot VIPs the moment they cross a spend threshold. - [Win-back](#uc-winback): Customers who used to buy and have gone quiet. - [Abandoned checkout](#uc-abandoned): Remind people who left checkout in the last day. - [Recently added to cart](#uc-recent): The last 5 products each shopper added. - [Country personalisation](#uc-country): The customer's latest shipping country. - [Real-time checks](#uc-realtime): "Is this shopper a VIP?" in one call, plus support lookups. ## High-value customers (segment + webhook) Uses: event: purchase · metrics: total_spend, order_count Spot VIPs the moment they cross a spend threshold. **You need:** the `purchase` event and the `total_spend` and `order_count` metrics from the [quickstart](https://docs.breezeiq.in/quickstart.md). Segment: spent 10,000+ over at least 2 orders: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments/vip-customers" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"workspace_id":"my-store","display_name":"VIP customers", "predicate":{"all":[{"metric":"total_spend","op":"gte","value":10000}, {"metric":"order_count","op":"gte","value":2}]}, "automations":{"on_enter":true,"on_exit":false,"on_backfill":false}}' ``` **Use it:** on each `entered` webhook, fetch the profile and tag the customer in your CRM or loyalty system. ## Win-back (time-based segment) Uses: event: purchase · metrics: last_order_at, total_spend Customers who used to buy and have gone quiet. **You need:** the `purchase` event and the `last_order_at` and `total_spend` metrics. Segment rule: bought before, quiet for 60+ days: ```json { "all": [ { "metric": "last_order_at", "op": "beyond_days", "value": 60 }, { "metric": "total_spend", "op": "gte", "value": 1000 } ] } ``` **Use it:** people age into this segment over time with no new event; BreezeIQ re-checks time-based rules periodically. Set `"on_backfill": true` if you want webhooks for those time-driven entries too. ## Abandoned checkout (time metric) Uses: event: abandonedcheckout · metric: last_abandoned_checkout_at Remind people who left checkout in the last day. **You need:** the `abandonedcheckout` event and a `last_abandoned_checkout_at` metric, created below. Metric: when they last abandoned a checkout: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"metric_name":"last_abandoned_checkout_at","event_name":"abandonedcheckout", "value_kind":"occurred_at_epoch","display_name":"Last abandoned checkout"}' ``` Segment rule: abandoned in the last day: ```json { "metric": "last_abandoned_checkout_at", "op": "within_days", "value": 1 } ``` **Use it:** send a reminder on `entered`. Customers drop out automatically after a day. ## Recently added to cart (list metric) Uses: event: addtocart · metric: recent_cart_adds The last 5 products each shopper added. **You need:** an add-to-cart event type (for example `addtocart`). Register it first and send it from the storefront with the product id. Then create the `recent_cart_adds` metric. Metric: last 5 distinct products added: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"metric_name":"recent_cart_adds","event_name":"addtocart","value_kind":"property_string", "value_path":"properties.product_id","aggregation":"recent","keep":5,"display_name":"Recent cart adds"}' ``` The profile then carries `"items": [{"value": "SKU-7", "at": "..."}, ...]`, newest first. A product added again moves back to the front. Cart adds made before login join the customer's list when they log in. Segment rule: added to cart in the last day: ```json { "metric": "recent_cart_adds", "op": "within_days", "value": 1 } ``` **Use it:** on `entered`, fetch the profile and render the items in a "still thinking about these?" message. ## Country personalisation (text metric) Uses: event: addshippinginfo · metric: country The customer's latest shipping country. **You need:** the `addshippinginfo` event and a `country` metric, created below. Metric: latest shipping country: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"metric_name":"country","event_name":"addshippinginfo","value_kind":"property_string", "value_path":"properties.country","aggregation":"latest","display_name":"Country"}' ``` The newest value by event time wins, so a delayed old event never overwrites a newer country. To also learn it from orders, add a second claim with `"event_name": "purchase"`. **Use it:** read `metrics[].text` from a [profile lookup](https://docs.breezeiq.in/api/profiles.md) to pick currency, language or shipping offers. ## Real-time checks & support lookups (read API) "Is this shopper in a segment right now?" in one call, no webhooks needed. **You need:** a segment, such as `vip-customers` from [High-value customers](#uc-vip), and a customer identifier. Membership check by email: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/segments/vip-customers/membership?type=email&value=priya@example.com" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "in_segment": true, "since": "2026-10-08T10:15:04Z", "profile_id": "60de1d6e-748f-87dc-ab33-bfbbaba9b299", "origin": "live-eval", "evaluated_version": 3, "as_of": "2026-10-08T11:02:10Z", "segment_status": "active" } ``` **Use it:** gate offers or content on `in_segment`. Support teams can pull a full customer view by phone or email with [profile lookup](https://docs.breezeiq.in/api/profiles.md): identifiers, every metric, and current segments. ## Next - [Metrics](https://docs.breezeiq.in/metrics.md): Value kinds, windows and value paths. - [Segments](https://docs.breezeiq.in/segments.md): Rule trees and operators. - [Webhooks](https://docs.breezeiq.in/webhooks.md): Payload and delivery rules. --- # Overview Base URL, authentication, errors and paging, plus every control-plane endpoint at a glance. The control-plane API configures BreezeIQ and reads its profiles, segments and members. ## Conventions | Base URL | `https://api.breeze.in/cdp/control-plane` | | --- | --- | | Format | JSON in and out (`Content-Type: application/json`) | | Auth | `Authorization: Bearer `, with a `cpt_...` or `cpw_...` token. See [Authentication](https://docs.breezeiq.in/authentication.md). | | Errors | `{"error": "human-readable message"}` with an HTTP status. See [Errors](https://docs.breezeiq.in/api/errors.md). | | Paging | List endpoints return `next_cursor`. Pass it back as `?cursor=`. `null` means the last page. | ## Scopes Each endpoint shows the token it needs. | Scope | Accepts | | --- | --- | | tenant | A tenant token (`cpt_...`) | | workspace | A tenant token, or that workspace's own token (`cpw_...`) | ## Endpoints ### [Workspaces](https://docs.breezeiq.in/api/workspaces.md) | Endpoint | Request | Scope | | --- | --- | --- | | [Create a workspace](https://docs.breezeiq.in/api/workspaces.md#create-a-workspace) | `POST /v1/tenants/{tenant}/workspaces` | tenant | | [List workspaces](https://docs.breezeiq.in/api/workspaces.md#list-workspaces) | `GET /v1/tenants/{tenant}/workspaces` | workspace | | [Add an alias](https://docs.breezeiq.in/api/workspaces.md#add-an-alias) | `PUT /v1/tenants/{tenant}/workspaces/{ws}/aliases/{alias}` | tenant | | [Remove an alias](https://docs.breezeiq.in/api/workspaces.md#remove-an-alias) | `DELETE /v1/tenants/{tenant}/workspaces/{ws}/aliases/{alias}` | tenant | ### [Tokens](https://docs.breezeiq.in/api/tokens.md) | Endpoint | Request | Scope | | --- | --- | --- | | [Check a token](https://docs.breezeiq.in/authentication.md#check-a-token) | `GET /v1/whoami` | any | | [Create a workspace token](https://docs.breezeiq.in/api/tokens.md#create-a-workspace-token) | `POST /v1/tenants/{tenant}/workspaces/{ws}/tokens` | tenant | | [List tokens](https://docs.breezeiq.in/api/tokens.md#list-tokens) | `GET /v1/tenants/{tenant}/tokens` | tenant | | [Revoke a token](https://docs.breezeiq.in/api/tokens.md#revoke-a-token) | `DELETE /v1/tenants/{tenant}/tokens/{token_id}` | tenant | ### [Event types](https://docs.breezeiq.in/api/event-types.md) | Endpoint | Request | Scope | | --- | --- | --- | | [Register an event type](https://docs.breezeiq.in/api/event-types.md#register-an-event-type) | `PUT /v1/tenants/{tenant}/event-types/{event_name}` | tenant | | [List event types](https://docs.breezeiq.in/api/event-types.md#list-event-types) | `GET /v1/tenants/{tenant}/event-types` | workspace | | [Delete an event type](https://docs.breezeiq.in/api/event-types.md#delete-an-event-type) | `DELETE /v1/tenants/{tenant}/event-types/{event_name}` | tenant | ### [Metric definitions](https://docs.breezeiq.in/api/metric-definitions.md) | Endpoint | Request | Scope | | --- | --- | --- | | [Create a metric definition](https://docs.breezeiq.in/api/metric-definitions.md#create-a-metric-definition) | `PUT /v1/tenants/{tenant}/metric-definitions` | tenant | | [List metric definitions](https://docs.breezeiq.in/api/metric-definitions.md#list-metric-definitions) | `GET /v1/tenants/{tenant}/metric-definitions` | workspace | | [Delete a metric definition](https://docs.breezeiq.in/api/metric-definitions.md#delete-a-metric-definition) | `DELETE /v1/tenants/{tenant}/metric-definitions` | tenant | ### [Segments](https://docs.breezeiq.in/api/segments.md) | Endpoint | Request | Scope | | --- | --- | --- | | [Preview a segment](https://docs.breezeiq.in/api/segments.md#preview-a-segment) | `POST /v1/tenants/{tenant}/segments/preview` | tenant | | [Create a segment](https://docs.breezeiq.in/api/segments.md#create-a-segment) | `PUT /v1/tenants/{tenant}/segments/{segment_id}` | tenant | | [List segments](https://docs.breezeiq.in/api/segments.md#list-segments) | `GET /v1/tenants/{tenant}/segments` | workspace | | [Get a segment](https://docs.breezeiq.in/api/segments.md#get-a-segment) | `GET /v1/tenants/{tenant}/segments/{segment_id}/definition` | workspace | | [Update segment status](https://docs.breezeiq.in/api/segments.md#update-segment-status) | `PUT /v1/tenants/{tenant}/segments/{segment_id}/status` | tenant | | [Delete a segment](https://docs.breezeiq.in/api/segments.md#delete-a-segment) | `DELETE /v1/tenants/{tenant}/segments/{segment_id}` | tenant | ### [Profiles](https://docs.breezeiq.in/api/profiles.md) | Endpoint | Request | Scope | | --- | --- | --- | | [Look up a profile](https://docs.breezeiq.in/api/profiles.md#look-up-a-profile) | `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles/lookup` | workspace | | [Get a profile](https://docs.breezeiq.in/api/profiles.md#get-a-profile) | `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles/{profile_id}` | workspace | | [List profile summaries](https://docs.breezeiq.in/api/profiles.md#list-profile-summaries) | `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles/summary` | workspace | | [List profiles](https://docs.breezeiq.in/api/profiles.md#list-profiles) | `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles` | workspace | | [Get profile segments](https://docs.breezeiq.in/api/profiles.md#get-profile-segments) | `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles/{profile_id}/segments` | workspace | | [Erase a profile](https://docs.breezeiq.in/api/profiles.md#erase-a-profile) | `DELETE /v1/tenants/{tenant}/workspaces/{ws}/profiles/{profile_id}` | tenant | ### [Segment members](https://docs.breezeiq.in/api/segment-members.md) | Endpoint | Request | Scope | | --- | --- | --- | | [Check membership](https://docs.breezeiq.in/api/segment-members.md#check-membership) | `GET /v1/tenants/{tenant}/workspaces/{ws}/segments/{segment_id}/membership` | workspace | | [List segment members](https://docs.breezeiq.in/api/segment-members.md#list-segment-members) | `GET /v1/tenants/{tenant}/workspaces/{ws}/segments/{segment_id}/members` | workspace | | [Export segment members](https://docs.breezeiq.in/api/segment-members.md#export-segment-members) | `GET /v1/tenants/{tenant}/segments/{segment_id}/members` | workspace | --- # Workspaces List and create workspaces, and manage their aliases. A workspace is one store or brand, with its own profiles, segments and members. Aliases route events that use another name for it, such as a shop domain. ### Create a workspace `POST /v1/tenants/{tenant}/workspaces` · Tenant token Creates a workspace. It is usable immediately: tenant-wide event types and metrics apply to it automatically. **Body** - `workspace_id` (string, required): 2–63 characters of `a-z 0-9 _ -`. No dots: put domains in `aliases`. - `display_name` (string, required): Human-readable name. - `aliases` (string[]): Other names events may use for this workspace, such as a shop domain. Request: ```bash curl -X POST "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{ "workspace_id": "my-store", "display_name": "My Store", "aliases": ["mystore.myshopify.com"] }' ``` 201 Created: ```json { "status": "created", "tenant_id": "breeze", "workspace_id": "my-store", "display_name": "My Store", "shard_id": 0, "aliases": ["mystore.myshopify.com"] } ``` Returns `409` if the id or an alias is taken. ### List workspaces `GET /v1/tenants/{tenant}/workspaces` · Workspace token Lists the tenant's workspaces. A workspace token only sees its own. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "workspaces": [ { "workspace_id": "my-store", "display_name": "My Store", "status": "active", "shard_id": 0, "aliases": ["mystore.myshopify.com"] } ] } ``` ### Add an alias `PUT /v1/tenants/{tenant}/workspaces/{ws}/aliases/{alias}` · Tenant token Adds an alias, such as a shop domain. Events sent with the alias are stored under the workspace. Takes effect within about 30 seconds. Request: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/aliases/mystore.myshopify.com" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` ### Remove an alias `DELETE /v1/tenants/{tenant}/workspaces/{ws}/aliases/{alias}` · Tenant token Removes the alias from the workspace. Request: ```bash curl -X DELETE "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/aliases/mystore.myshopify.com" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` --- # Tokens Mint, list and revoke workspace tokens. Workspace tokens (`cpw_...`) are read-only and see one workspace ([scopes](https://docs.breezeiq.in/authentication.md)). Tenant tokens are issued by the BreezeIQ team, not through the API. ### Create a workspace token `POST /v1/tenants/{tenant}/workspaces/{ws}/tokens` · Tenant token Mints a read-only workspace token, for a dashboard or app. No body. Request: ```bash curl -X POST "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/tokens" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 201 Created: ```json { "token": "cpw_dad43ab7f2a5.9c1f…", "token_id": "cpw_dad43ab7f2a5", "tenant_id": "breeze", "workspace_id": "my-store", "note": "store this token now — it is not retrievable again" } ``` > **The token is shown once:** Store `token` as soon as you receive it. It can't be retrieved again. ### List tokens `GET /v1/tenants/{tenant}/tokens` · Tenant token Lists tokens, never their secrets. `workspace_id: null` marks a tenant token. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/tokens" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "tokens": [ { "token_id": "cpw_dad43ab7f2a5", "workspace_id": "my-store", "status": "active" } ] } ``` ### Revoke a token `DELETE /v1/tenants/{tenant}/tokens/{token_id}` · Tenant token Revokes a token immediately. Request: ```bash curl -X DELETE "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/tokens/cpw_dad43ab7f2a5" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` Response: ```json { "status": "revoked", "token_id": "…" } ``` --- # Event types Register event names and how their events are deduplicated. Every event name must be registered before BreezeIQ accepts it. Registering also decides how that event type is deduplicated. ### Register an event type `PUT /v1/tenants/{tenant}/event-types/{event_name}` · Tenant token Creates the event type, or updates it if it exists. Names are lowercase. BreezeIQ accepts a new event type within a few minutes. **Body** - `dedup_entity` (string): Business entity the event is about, such as `"order"`. - `dedup_key_paths` (string[]): Paths that identify that entity, such as `["properties.order_id"]`. Give both fields or neither. Without them, events are deduplicated by their `id`. Request: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/event-types/purchase" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"dedup_entity": "order", "dedup_key_paths": ["properties.order_id"]}' ``` 200 OK: ```json { "tenant_id": "breeze", "event_name": "purchase", "status": "upserted" } ``` Deduplication is per event type: `initiatecheckout` and `addpaymentinfo` can share a `checkout_id` without colliding. > **The collector has its own allow-list:** Besides this registration, the collector keeps a list of allowed event names. If your events come back counted under `filtered`, ask the BreezeIQ team to allow the name there. ### List event types `GET /v1/tenants/{tenant}/event-types` · Workspace token Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/event-types" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "event_types": [ { "event_name": "purchase", "dedup_entity": "order", "dedup_key_paths": ["properties.order_id"], "status": "active" }, { "event_name": "initiatecheckout", "dedup_entity": "checkout", "dedup_key_paths": ["properties.checkout_id"], "status": "active" } ] } ``` ### Delete an event type `DELETE /v1/tenants/{tenant}/event-types/{event_name}` · Tenant token Removes the event type. --- # Metric definitions Define, list and delete the metrics kept on every profile. A metric definition (also called a claim) tells BreezeIQ which value to keep on each profile from one event type. See [Metrics](https://docs.breezeiq.in/metrics.md) for value kinds and examples. ### Create a metric definition `PUT /v1/tenants/{tenant}/metric-definitions` · Tenant token Creates a claim. Create-only: returns `409` if this (metric, event) pair already exists. **Body** - `metric_name` (string, required): Name shown on profiles and used in segments. - `event_name` (string, required): A registered event type. - `value_kind` (string, required): `count`, `property_number`, `occurred_at_epoch` or `property_string`. See [Metrics](https://docs.breezeiq.in/metrics.md). - `value_path` (string): Required for `property_number` and `property_string`, such as `"properties.amount"`. - `aggregation` (string): `property_string` only, and required there: `"latest"` or `"recent"`. - `keep` (number): `recent` only: list length, 1–10. Default `5`. - `window_days` (number): 1–730, for `count` and `property_number`: a rolling window. - `workspace_id` (string): `"*"` (default) for every workspace, or one workspace id. - `display_name` (string): Label. - `description` (string): Label. Request: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{ "metric_name": "spend_last_30d", "event_name": "purchase", "value_kind": "property_number", "value_path": "properties.amount", "window_days": 30, "display_name": "Spend (30 days)" }' ``` 200 OK: ```json { "tenant_id": "breeze", "metric_name": "spend_last_30d", "status": "created" } ``` Takes effect within about a minute. Invalid combinations return `422` with the reason, for example `"aggregation 'latest' takes no keep"`. ### List metric definitions `GET /v1/tenants/{tenant}/metric-definitions` · Workspace token Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "metric_definitions": [ { "workspace_id": "*", "metric_name": "total_spend", "event_name": "purchase", "value_kind": "property_number", "value_path": "properties.amount", "display_name": "Total spend", "description": null, "window_days": null, "aggregation": null, "keep": null }, { "workspace_id": "*", "metric_name": "recent_cart_adds", "event_name": "addtocart", "value_kind": "property_string", "value_path": "properties.product_id", "display_name": "Recent cart adds", "description": null, "window_days": null, "aggregation": "recent", "keep": 5 } ] } ``` ### Delete a metric definition `DELETE /v1/tenants/{tenant}/metric-definitions` · Tenant token Stops collecting a claim. Values already computed keep their last value. **Query** - `metric_name` (string): The metric to stop. - `event_name` (string): The event type it reads from. - `workspace_id` (string): Defaults to `*`. Request: ```bash curl -X DELETE "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/metric-definitions?metric_name=spend_last_30d&event_name=purchase" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` --- # Segments Preview, create, list, pause and delete segments. A segment is a saved rule over metrics. See [Segments](https://docs.breezeiq.in/segments.md) for how to write the `predicate`. ### Preview a segment `POST /v1/tenants/{tenant}/segments/preview` · Tenant token Validates a rule and counts who would match, without saving anything. Good for live previews in a rule editor. **Body** - `workspace_id` (string): The workspace to count in. - `predicate` (object): The rule. See [Segments](https://docs.breezeiq.in/segments.md). Request: ```bash curl -X POST "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments/preview" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{ "workspace_id": "my-store", "predicate": { "metric": "total_spend", "op": "gte", "value": 10000 } }' ``` 200 OK: ```json { "matching_customers": 3, "matching_breakdown": { "customers": 2, "visitors": 1 }, "workspace_members": 15, "workspace_customers": 11, "workspace_visitors": 4, "truncated": false, "is_temporal": false } ``` Matches are counted over at most 20,000 profiles. `truncated: true` means the counts are a lower bound. The `workspace_*` totals are always exact. ### Create a segment `PUT /v1/tenants/{tenant}/segments/{segment_id}` · Tenant token Creates a segment. Create-only: returns `409` if the id exists. **Body** - `workspace_id` (string, required): The workspace the segment lives in. - `display_name` (string, required): Human-readable name. - `predicate` (object, required): The rule. See [Segments](https://docs.breezeiq.in/segments.md). - `status` (string): `draft`, `active` (default), `paused` or `archived`. - `automations` (object): Default `{"on_enter": true, "on_exit": true, "on_backfill": false}`. Request: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments/vip-customers" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{ "workspace_id": "my-store", "display_name": "VIP customers", "predicate": { "metric": "total_spend", "op": "gte", "value": 10000 } }' ``` 200 OK: ```json { "tenant_id": "breeze", "segment_id": "vip-customers", "is_temporal": false, "status": "created" } ``` ### List segments `GET /v1/tenants/{tenant}/segments` · Workspace token Lists segments with live member counts. **Query** - `workspace_id` (string): The workspace to list. - `limit` (number): Page size, up to 500. - `cursor` (string): `next_cursor` from the previous page. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments?workspace_id=my-store&limit=100" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "segments": [ { "workspace_id": "my-store", "segment_id": "vip-customers", "display_name": "VIP customers", "predicate": { "metric": "total_spend", "op": "gte", "value": 10000 }, "is_temporal": false, "status": "active", "automations": { "on_enter": true, "on_exit": true, "on_backfill": false }, "created_at": "2026-10-08T09:00:00Z", "member_count": 12, "segment_customers": 9, "segment_visitors": 3 } ], "next_cursor": null } ``` ### Get a segment `GET /v1/tenants/{tenant}/segments/{segment_id}/definition` · Workspace token Returns one segment, in the same shape as [List segments](#list-segments) without the counts. **Query** - `workspace_id` (string): The segment's workspace. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments/vip-customers/definition?workspace_id=my-store" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` ### Update segment status `PUT /v1/tenants/{tenant}/segments/{segment_id}/status` · Tenant token Changes the status, the only field that can change after creation. **Body** - `workspace_id` (string): The segment's workspace. - `status` (string): `draft`, `active`, `paused` or `archived`. Request: ```bash curl -X PUT "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments/vip-customers/status" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" -H "Content-Type: application/json" \ -d '{"workspace_id": "my-store", "status": "paused"}' ``` ### Delete a segment `DELETE /v1/tenants/{tenant}/segments/{segment_id}` · Tenant token Deletes a segment definition. Use it for mistakes. For normal retirement, prefer [`status: "archived"`](#update-segment-status). **Query** - `workspace_id` (string): The segment's workspace. Request: ```bash curl -X DELETE "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments/vip-customers?workspace_id=my-store" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` --- # Profiles Look up, list and erase profiles. Read customer profiles: find one by identifier or id, page through a workspace, or erase a customer. See [Profiles](https://docs.breezeiq.in/profiles.md) for how profiles form. ### Look up a profile `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles/lookup` · Workspace token Finds the profile that holds an identifier. Returns `404` if no profile has it. **Query** - `type` (string): Identifier type, such as `email` or `phone`. - `value` (string): Identifier value. It is normalised the same way as at ingestion, so any capitalisation of an email, or a phone number without `+91`, still matches. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/profiles/lookup?type=phone&value=9812345678" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "profile_id": "60de1d6e-748f-87dc-ab33-bfbbaba9b299", "workspace_id": "my-store", "status": "active", "profile_type": "customer", "component_version": 3, "created_at": "2026-10-08T10:15:02Z", "identifiers": [ { "type": "email", "tier": "strong", "value": "priya@example.com", "masked_value": "pr****@example.com", "key": "9f2c…", "status": "active" }, { "type": "cookie", "tier": "weak", "value": null, "masked_value": "3f9a****", "key": "52a9…", "status": "active" } ], "metrics": [ { "metric": "total_spend", "display_name": "Total spend", "value": "2499", "stamped_version": 3 }, { "metric": "country", "display_name": "Country", "value": "1791364450", "text": "IN", "stamped_version": 3 } ], "segments": [ { "segment_id": "vip-customers", "display_name": "VIP customers", "state": "entered", "origin": "live-eval", "entered_at": "2026-10-08T10:15:04Z", "exited_at": null } ] } ``` The response is the profile view: - Metric values are strings so exact decimals survive. Time metrics are Unix seconds. - Identifier `value` is shown in plain text only for types your environment allows (typically email and phone). Otherwise it is `null` and only `masked_value` is returned. ### Get a profile `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles/{profile_id}` · Workspace token Returns the same profile view as [Look up a profile](#look-up-a-profile), by id. Ids of merged-away profiles resolve to the surviving profile. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/profiles/60de1d6e-748f-87dc-ab33-bfbbaba9b299" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` ### List profile summaries `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles/summary` · Workspace token A customer table: one row per profile with contact details and order headline metrics. `email` and `phone` are plain text only for types your environment allows, otherwise masked. **Query** - `limit` (number): Page size: 25 by default, up to 200. - `cursor` (string): `next_cursor` from the previous page. - `profile_type` (string): Only profiles of this type, such as `customer`. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/profiles/summary?limit=50" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "profiles": [ { "profile_id": "199c5179-51b5-8f34-89c6-dc79ba84d656", "profile_type": "customer", "email": "rahul@example.com", "phone": "+919812345678", "total_spend": "899", "order_count": "1", "last_order_at": "1788784963", "created_at": "2026-09-10T17:44:09Z" } ], "next_cursor": "1ffb5492-…", "workspace_members": 13, "workspace_customers": 7, "workspace_visitors": 6 } ``` ### List profiles `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles` · Workspace token Profiles with their display identifiers. **Query** - `limit` (number): Page size, up to 200. - `cursor` (string): `next_cursor` from the previous page. - `profile_type` (string): Only profiles of this type, such as `customer`. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/profiles?limit=50" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` ### Get profile segments `GET /v1/tenants/{tenant}/workspaces/{ws}/profiles/{profile_id}/segments` · Workspace token Just the profile's segment memberships, with display names. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/profiles/60de1d6e-748f-87dc-ab33-bfbbaba9b299/segments" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` ### Erase a profile `DELETE /v1/tenants/{tenant}/workspaces/{ws}/profiles/{profile_id}` · Tenant token Permanently erases a customer, for example for a GDPR request: the profile and everything merged into it, every identifier, metric, segment membership and history entry. > **Erasing is irreversible:** There is no undo. The profile and all of its data are gone once this returns. Request: ```bash curl -X DELETE "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/profiles/9dc94bd5-31f3-855c-945b-d66a759f5c78" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "deleted_root": "9dc94bd5-31f3-855c-945b-d66a759f5c78", "deleted": { "profiles": 1, "identifiers": 3, "metric_contribution": 5, "canonical_metrics": 5, "segment_membership": 0, "segment_transition_log": 0 }, "redis_mappings_deleted": 3 } ``` --- # Segment members Check one customer, list a segment, or export it in bulk. Check one customer's membership, list the people in a segment, or export a whole audience. ### Check membership `GET /v1/tenants/{tenant}/workspaces/{ws}/segments/{segment_id}/membership` · Workspace token Is one customer in the segment right now? **Query** - `type` (string): Identifier type, such as `email` or `phone`. - `value` (string): Identifier value. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/segments/vip-customers/membership?type=email&value=priya@example.com" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "in_segment": true, "since": "2026-10-08T10:15:04Z", "profile_id": "60de1d6e-…", "origin": "live-eval", "evaluated_version": 3, "as_of": "2026-10-08T11:02:10Z", "segment_status": "active" } ``` An unknown identifier returns `200` with `in_segment: false`. An unknown segment returns `404`. ### List segment members `GET /v1/tenants/{tenant}/workspaces/{ws}/segments/{segment_id}/members` · Workspace token The people in a segment, with contacts and headline metrics. **Query** - `limit` (number): Page size: 50 by default, up to 200. - `cursor` (string): `next_cursor` from the previous page. - `profile_type` (string): Only members of this type, such as `customer`. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/segments/vip-customers/members?limit=50" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "segment_id": "vip-customers", "members": [ { "profile_id": "60de1d6e-…", "profile_type": "customer", "email": "priya@example.com", "phone": "+919812345678", "total_spend": "12499", "order_count": "3", "last_order_at": "1791370287", "entered_at": "2026-10-08T10:15:04Z" } ], "next_cursor": null, "total_members": 3, "segment_customers": 2, "segment_visitors": 1, "workspace_members": 11, "workspace_customers": 7, "workspace_visitors": 4 } ``` ### Export segment members `GET /v1/tenants/{tenant}/segments/{segment_id}/members` · Workspace token Bulk export with profile ids only. Use it for syncing a whole audience. **Query** - `workspace_id` (string): The segment's workspace. - `cursor` (string): `next_cursor` from the previous page. - `limit` (number): Page size: 1,000 by default, up to 5,000. Request: ```bash curl "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/segments/vip-customers/members?workspace_id=my-store&limit=5000" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "segment_id": "vip-customers", "members": [ { "profile_id": "60de1d6e-…", "entered_at": "2026-10-08T10:15:04Z", "origin": "live-eval" } ], "next_cursor": "03746e3b-…" } ``` --- # Errors The error shape and what each status code means. ## Error shape Every non-2xx response has the same shape. The message names the problem. Error response: ```json { "error": "unknown metric 'total_spnd' — define it first (metric-definitions)" } ``` ## Status codes | Status | Meaning | | --- | --- | | `401` | Missing or invalid token | | `403` | Valid token, wrong scope: another tenant or workspace, or a write with a workspace token | | `404` | No such resource (profile, segment, identifier) | | `409` | Already exists, and this resource is create-only (metric claims, segments, workspaces) | | `422` | The body failed validation; the message says exactly why | | `503` | A backing store is temporarily unavailable; retry | --- # Data & privacy How personal data is stored, masked, kept out of webhooks, and erased on request. This page collects, in one place, how BreezeIQ handles personal data: what it stores, who can read it, what leaves it, and how to erase a customer. Each point links to the page with the details. ## What's stored You never write profiles directly. BreezeIQ derives them from the events you send ([Concepts](https://docs.breezeiq.in/concepts.md)). The personal data it keeps is the identifiers in those events. | Data | How it's handled | | --- | --- | | Identifier values | Encrypted at rest. See [Identifiers](https://docs.breezeiq.in/identifiers.md). | | Identifier types | Only the types your tenant declares count. Unknown types in an event are ignored. | | `email` | Trimmed and lowercased before matching. | | `phone` | Normalised to E.164. Numbers without a country code are treated as Indian. | | Placeholder values | Values configured as "noise" (such as `test@example.com`) are ignored entirely and never link anyone. Ask the BreezeIQ team to add yours. | | Metrics, segment memberships, history | Derived per profile from events. See [Profiles & identity](https://docs.breezeiq.in/profiles.md). | ### Browser events can't carry contact details The browser endpoint needs no token, so anyone can call it. BreezeIQ keeps only `cookie` and `device_id` from it; email and phone are dropped, because anyone could claim them. Browser events also never merge two existing profiles. Send email and phone only from your server, with the collector token. See [From the browser](https://docs.breezeiq.in/browser-events.md) and [From your server](https://docs.breezeiq.in/server-events.md). ## Who can see what Data is isolated per tenant and per workspace. Each workspace (one store or brand) has its own profiles, segments and members. Identities, metrics and segments never cross workspaces: the same customer in two workspaces is two separate profiles. | Token | Can read | Can write | | --- | --- | --- | | Tenant (`cpt_...`) | Everything in the tenant, all workspaces | Configuration, workspace tokens, profile erasure. Issued by the BreezeIQ team, not through the API. | | Workspace (`cpw_...`) | That workspace's profiles, segments and members, plus the tenant's event types and metric definitions | Nothing. Read-only. | - A token can never see another tenant's data, and a workspace token can never see another workspace's data. Both return `403`, as does a write with a workspace token. See [Errors](https://docs.breezeiq.in/api/errors.md). - A workspace token is shown once, when it's minted, and can't be retrieved again. Listing tokens never returns their secrets. See [Tokens](https://docs.breezeiq.in/api/tokens.md). - Revoking a token takes effect immediately. - Check what a token can do with `GET /v1/whoami`. See [Authentication](https://docs.breezeiq.in/authentication.md). ## What leaves BreezeIQ ### Webhooks carry ids only Segment webhooks contain no personal data: identifiers never appear in them. A payload names the change with `tenant_id`, `workspace_id`, `segment_id` and `profile_id`. Your receiver calls the profile API for emails, phones and metrics. The webhook URL is set per environment by the BreezeIQ team. See [Webhooks](https://docs.breezeiq.in/webhooks.md). ### The profile API masks identifiers Profile views return an identifier's `value` in plain text only for types your environment allows (typically email and phone). For other types, `value` is `null` and only `masked_value` is returned. The customer table (`profiles/summary`) and segment member lists follow the same rule for their `email` and `phone` columns, showing the masked value where plain text isn't allowed. See [Profiles API](https://docs.breezeiq.in/api/profiles.md). Identifiers in a profile view: ```json "identifiers": [ { "type": "email", "tier": "strong", "value": "priya@example.com", "masked_value": "pr****@example.com", "key": "9f2c…", "status": "active" }, { "type": "cookie", "tier": "weak", "value": null, "masked_value": "3f9a****", "key": "52a9…", "status": "active" } ] ``` ## Erase a customer To act on a deletion request (for example under GDPR), call [Erase a profile](https://docs.breezeiq.in/api/profiles.md#erase-a-profile) (`DELETE .../profiles/{profile_id}`) with a tenant token. It permanently erases: - the profile and every profile merged into it - every identifier - every metric - every segment membership - every history entry Find the `profile_id` with a profile lookup by email or phone. The response counts what was deleted. See [Profiles API](https://docs.breezeiq.in/api/profiles.md). Request: ```bash curl -X DELETE "https://api.breeze.in/cdp/control-plane/v1/tenants/breeze/workspaces/my-store/profiles/9dc94bd5-31f3-855c-945b-d66a759f5c78" \ -H "Authorization: Bearer $BREEZEIQ_TOKEN" ``` 200 OK: ```json { "deleted_root": "9dc94bd5-31f3-855c-945b-d66a759f5c78", "deleted": { "profiles": 1, "identifiers": 3, "metric_contribution": 5, "canonical_metrics": 5, "segment_membership": 0, "segment_transition_log": 0 }, "redis_mappings_deleted": 3 } ``` > **Erasure is irreversible:** A deleted profile can't be restored. The call needs a tenant token; workspace tokens are read-only. ## Next - [Identifiers](https://docs.breezeiq.in/identifiers.md): Types, normalisation and rules. - [Authentication](https://docs.breezeiq.in/authentication.md): Tenant and workspace tokens. - [Webhooks](https://docs.breezeiq.in/webhooks.md): Segment changes, ids only. - [Profiles API](https://docs.breezeiq.in/api/profiles.md): Look up and erase profiles. --- # Limits & timings Size limits, page sizes, and how long each step takes to apply. ## Timings How long a change takes to apply. | What | Typical time | | --- | --- | | Event to profile and metrics | Usually a few seconds ([Delivery](https://docs.breezeiq.in/delivery.md)) | | New metric definition takes effect | About 1 minute ([Metrics](https://docs.breezeiq.in/metrics.md)) | | New segment evaluates existing customers | Starts within about 1 minute; large workspaces take longer ([Segments](https://docs.breezeiq.in/segments.md)) | | New event type accepted by BreezeIQ | Within a few minutes ([Event types](https://docs.breezeiq.in/api/event-types.md)) | | New workspace alias | About 30 seconds ([Workspaces](https://docs.breezeiq.in/api/workspaces.md)) | ## Limits Sizes, counts and page sizes. | What | Limit | | --- | --- | | Identifier values per event | 10 | | Text metric value length | 128 characters | | `recent` list length (`keep`) | 1–10 | | `window_days` | 1–730 | | Segment rule nesting | 8 levels | | Segment preview scan | 20,000 profiles | | Page size: profiles | 200 | | Page size: segment members | 200 | | Page size: segments | 500 | | Page size: bulk members | 5,000 | ## Next - [Troubleshooting](https://docs.breezeiq.in/troubleshooting.md): Missing events, empty metrics and segments. - [Errors](https://docs.breezeiq.in/api/errors.md): Control-plane status codes. --- # Troubleshooting Fixes for events that don't show up, empty metrics and empty segments. Find your symptom, then work through the checks in order. ## An event doesn't show on the profile A collector `200` only means the event was queued; an event that fails validation afterwards doesn't appear on any profile. For other collector status codes, see [Delivery](https://docs.breezeiq.in/delivery.md). 1. Check the event name is [registered](https://docs.breezeiq.in/api/event-types.md) and lowercase. 2. Check `occured_at` and `envelop_version` are spelled exactly like that. See [Events](https://docs.breezeiq.in/events.md). 3. Check the event carries at least one identifier of a declared type. From the browser, only `cookie` and `device_id` count. See [Identifiers](https://docs.breezeiq.in/identifiers.md). 4. Check `workspace_id` is set. Without it, the event lands in `default`. See [Events](https://docs.breezeiq.in/events.md). 5. Look the customer up with [profile lookup](https://docs.breezeiq.in/api/profiles.md), using an identifier you sent. ## A metric is empty 1. Check the events arrived after the definition took effect. Metrics only count events received after the definition was created, about a minute after you create it. See [Limits & timings](https://docs.breezeiq.in/limits.md). 2. Check `value_path` matches the event. It starts with `properties.`. See [Metrics](https://docs.breezeiq.in/metrics.md). 3. Check the value is a number for `property_number`. See [Metrics](https://docs.breezeiq.in/metrics.md). ## A segment has nobody in it 1. Run the rule through [preview](https://docs.breezeiq.in/api/segments.md). 2. Check for conditions on metrics new customers don't have yet. A condition on a missing metric is false, so customers without that metric are never in. See [Segments](https://docs.breezeiq.in/segments.md). ## Next - [Delivery](https://docs.breezeiq.in/delivery.md): Collector status codes and retries. - [Errors](https://docs.breezeiq.in/api/errors.md): Control-plane status codes. --- # FAQ Short answers to common questions about workspaces, identity, changes and deletion. ## Identity ### Can the same customer exist in two workspaces? Yes, as two separate profiles. Workspaces are fully isolated: identities, metrics and segments never cross them. See [Concepts](https://docs.breezeiq.in/concepts.md). ### What happens to an anonymous visitor's history when they log in? The first server-side event that carries both their cookie and their email (login, order) links them. The visitor's events, metrics and recent-item lists merge into the customer's profile and are recalculated, ordered by event time. See [Profiles & identity](https://docs.breezeiq.in/profiles.md). ## Data ### Do duplicates or retries inflate my numbers? No. Each event is counted once, by its `id` or by the event type's business key (such as `order_id`). Retry freely. See [Delivery](https://docs.breezeiq.in/delivery.md). ### How do I delete a customer's data? Call `DELETE .../profiles/{profile_id}` with a tenant token. It erases the customer and everything linked to them, and can't be undone. See [Data & privacy](https://docs.breezeiq.in/privacy.md) and [Profiles API](https://docs.breezeiq.in/api/profiles.md). ### Where do webhooks go? To the endpoint configured for your environment by the BreezeIQ team. Every payload includes `tenant_id`, `workspace_id` and `segment_id` so one receiver can route them all. See [Webhooks](https://docs.breezeiq.in/webhooks.md). ## Metrics and segments ### Can I change a metric or a segment rule? Not in place, so existing values never silently change meaning. Create a new metric name or segment id (or delete and recreate the metric). A segment's `status` can be changed any time. See [Metric definitions](https://docs.breezeiq.in/api/metric-definitions.md) and [Segments API](https://docs.breezeiq.in/api/segments.md). ### Can segments match text, like country = "IN"? Not yet. Text and list metrics support `exists`, `missing`, `within_days` and `beyond_days` in segments. Read the text value from the profile for personalisation. See [Segments](https://docs.breezeiq.in/segments.md) and [Use cases](https://docs.breezeiq.in/use-cases.md).