Public API: Segments
A custom segment is a named group of values that describes your visitors, for example a plan segment with the values free, pro, and enterprise. Your snippet code sends each visitor's segment value with avsb.track.segment(). An experiment's results page can then filter or break its numbers down by those values, so you can see how each group performed.
A segment does not choose who sees an experiment. Use an audience for that instead: a named group of visitors defined by targeting rules. A segment only slices results you already collected, after the fact.
Segments are organization-scoped, so this API is org-level: the path carries no {orgId}, since the org is taken from your service token. A segment can optionally belong to a project (set projectId when you create it); leave it off for an org-wide segment.
https://app.avsb.cloud/api/v1/segmentsEvery endpoint here follows the shared conventions: the { data } envelope, an Idempotency-Key on every write below, and the standard error shape. Every /api/v1 token is rate-limited the same way everywhere: a scoped token gets 600 reads and 120 writes per minute, and an admin:* token gets 600 requests per minute, reads and writes together. Every endpoint here also needs the Integrations and API access plan feature, or every call fails with 403 feature_disabled. See rate-limit headers and Refusals at 403.
When commerce tracking is on, the snippet automatically sends two segment values for every visitor. cart_band is their cart total, bucketed. purchaser says whether they have bought before. Both are built-in segments: they reach AvsB right away and show up as a results filter and breakdown on their own, so you do not need to create a segment here for either key.
Scopes
A scope is a named permission on your token. It decides exactly what that token is allowed to read or change.
| Operation | Scope |
|---|---|
| List segments, get one segment | segments:read |
| Create, update, delete a segment | segments:write |
List segments
GET /api/v1/segments: every segment in the org, newest first. Cursor-paginated (?limit= up to 100, defaulting to 20; ?cursor=). Pass ?projectId= to return that project's segments together with the org-wide ones.
curl "https://app.avsb.cloud/api/v1/segments?limit=20" \ -H "Authorization: Bearer avsb_svc_..."const res = await fetch('https://app.avsb.cloud/api/v1/segments?limit=20', { headers: { Authorization: `Bearer ${process.env.AVSB_SERVICE_TOKEN}` },})const { data } = await res.json()import os, requestsres = requests.get( "https://app.avsb.cloud/api/v1/segments", params={"limit": 20}, headers={"Authorization": f"Bearer {os.environ['AVSB_SERVICE_TOKEN']}"},)data = res.json()["data"]{ "data": [ { "id": "<segmentId>", "shortId": 3, "projectId": "<projectId>", "name": "Plan tier", "key": "plan", "description": "", "values": ["free", "pro", "enterprise"], "createdAt": "2026-06-16T00:00:00.000Z", "updatedAt": "2026-06-16T00:00:00.000Z" } ], "page": { "nextCursor": null, "hasMore": false }}{ "error": { "code": "pagination_invalid", "message": "cursor is malformed", "docUrl": "https://docs.avsb.cloud/docs/developer-reference/public-api/conventions#cursor-pagination", "requestId": "req_9f2c41ab7e0b4d1e8c35a6f0d2b91e77" }}Create a segment
POST /api/v1/segments: name and key are required. name is 1 to 200 characters. The key may contain only letters, digits, and underscores, must be 1 to 100 characters, and must be unique within your organization. values is optional and defaults to an empty list; add entries later with an update. projectId is optional (and, when set, must name a project in your token's org).
The smallest working request sends just a name and a key:
curl -X POST https://app.avsb.cloud/api/v1/segments \ -H "Authorization: Bearer avsb_svc_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "name": "Plan tier", "key": "plan" }'const res = await fetch('https://app.avsb.cloud/api/v1/segments', { method: 'POST', headers: { Authorization: `Bearer ${process.env.AVSB_SERVICE_TOKEN}`, 'Content-Type': 'application/json', 'Idempotency-Key': crypto.randomUUID(), }, body: JSON.stringify({ name: 'Plan tier', key: 'plan' }),})const { data } = await res.json()import os, uuid, requestsres = requests.post( "https://app.avsb.cloud/api/v1/segments", headers={ "Authorization": f"Bearer {os.environ['AVSB_SERVICE_TOKEN']}", "Idempotency-Key": str(uuid.uuid4()), }, json={"name": "Plan tier", "key": "plan"},)data = res.json()["data"]Add starting values, a description, and a projectId to scope the segment to one project:
{ "name": "Plan tier", "key": "plan", "description": "Which paid tier the visitor is on", "values": ["free", "pro", "enterprise"], "projectId": "<projectId>"}{ "data": { "id": "<segmentId>", "shortId": 3, "projectId": "<projectId>", "name": "Plan tier", "key": "plan", "description": "Which paid tier the visitor is on", "values": ["free", "pro", "enterprise"], "createdAt": "2026-06-16T00:00:00.000Z", "updatedAt": "2026-06-16T00:00:00.000Z" }}A segment's key is fixed at creation: it cannot be changed by an update. Reusing a key already taken in your organization returns 409 conflict with "field": "key".
{ "error": { "code": "conflict", "message": "A segment with this key already exists", "details": { "field": "key" }, "docUrl": "https://docs.avsb.cloud/docs/developer-reference/public-api/conventions#conflict-errors", "requestId": "req_9f2c41ab7e0b4d1e8c35a6f0d2b91e77" }}Get a segment
GET /api/v1/segments/{segmentId}: one segment by id. A segment outside your org returns 404.
curl https://app.avsb.cloud/api/v1/segments/<segmentId> \ -H "Authorization: Bearer avsb_svc_..."const segmentId = '<segmentId>'const res = await fetch(`https://app.avsb.cloud/api/v1/segments/${segmentId}`, { headers: { Authorization: `Bearer ${process.env.AVSB_SERVICE_TOKEN}` },})const { data } = await res.json()import os, requestssegment_id = "<segmentId>"res = requests.get( f"https://app.avsb.cloud/api/v1/segments/{segment_id}", headers={"Authorization": f"Bearer {os.environ['AVSB_SERVICE_TOKEN']}"},)data = res.json()["data"]{ "error": { "code": "not_found", "message": "Segment not found", "docUrl": "https://docs.avsb.cloud/docs/developer-reference/public-api/conventions#not-found-errors", "requestId": "req_9f2c41ab7e0b4d1e8c35a6f0d2b91e77" }}Update a segment
PATCH /api/v1/segments/{segmentId}: partial update of name, description, values, or projectId. Sending values replaces the whole list; it does not add to it. The key is immutable; sending any unknown field is rejected.
curl -X PATCH https://app.avsb.cloud/api/v1/segments/<segmentId> \ -H "Authorization: Bearer avsb_svc_..." \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{ "values": ["free", "pro", "enterprise", "trial"] }'const segmentId = '<segmentId>'const res = await fetch(`https://app.avsb.cloud/api/v1/segments/${segmentId}`, { method: 'PATCH', headers: { Authorization: `Bearer ${process.env.AVSB_SERVICE_TOKEN}`, 'Content-Type': 'application/json', 'Idempotency-Key': crypto.randomUUID(), }, body: JSON.stringify({ values: ['free', 'pro', 'enterprise', 'trial'] }),})const { data } = await res.json()import os, uuid, requestssegment_id = "<segmentId>"res = requests.patch( f"https://app.avsb.cloud/api/v1/segments/{segment_id}", headers={ "Authorization": f"Bearer {os.environ['AVSB_SERVICE_TOKEN']}", "Idempotency-Key": str(uuid.uuid4()), }, json={"values": ["free", "pro", "enterprise", "trial"]},)data = res.json()["data"]{ "data": { "id": "<segmentId>", "shortId": 3, "projectId": "<projectId>", "name": "Plan tier", "key": "plan", "description": "Which paid tier the visitor is on", "values": ["free", "pro", "enterprise", "trial"], "createdAt": "2026-06-16T00:00:00.000Z", "updatedAt": "2026-06-17T09:00:00.000Z" }}A segment outside your org returns 404, the same shape as Get a segment above. Sending X-Avsb-If-Match from a prior read's ETag makes the write conditional: a segment that changed since you read it is refused with 412 instead of overwritten. See ETag / If-Match.
Delete a segment
DELETE /api/v1/segments/{segmentId}: removes the segment from your organization.
curl -X DELETE https://app.avsb.cloud/api/v1/segments/<segmentId> \ -H "Authorization: Bearer avsb_svc_..." \ -H "Idempotency-Key: $(uuidgen)"const segmentId = '<segmentId>'const res = await fetch(`https://app.avsb.cloud/api/v1/segments/${segmentId}`, { method: 'DELETE', headers: { Authorization: `Bearer ${process.env.AVSB_SERVICE_TOKEN}`, 'Idempotency-Key': crypto.randomUUID(), },})const { data } = await res.json()import os, uuid, requestssegment_id = "<segmentId>"res = requests.delete( f"https://app.avsb.cloud/api/v1/segments/{segment_id}", headers={ "Authorization": f"Bearer {os.environ['AVSB_SERVICE_TOKEN']}", "Idempotency-Key": str(uuid.uuid4()), },)data = res.json()["data"]{ "data": { "id": "<segmentId>", "deleted": true }}Deleting a segment does not change what any experiment targets: nothing in AvsB links a segment to an experiment or an audience. It only stops the segment from being a filter or breakdown option on results pages from then on.