{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://raw.githubusercontent.com/api-evangelist/infiniteaudience-ai/main/json-schema/infiniteaudience-ai-campaign-schema.json", "title": "Campaign", "description": "A named workspace grouping related audiences and deliveries. There is no audience_ids[] field — audiences[] (below) is the only audience-linkage field the handler ever returns.\n", "x-generated": "2026-10-09", "x-method": "derived", "x-generator": "derive-json-schema.py", "x-source": "openapi/infiniteaudience-ai-openapi.yml#/components/schemas/Campaign", "type": "object", "required": [ "id", "name", "description", "status", "audiences", "created_at", "updated_at" ], "properties": { "id": { "type": "string", "description": "Unique campaign identifier." }, "name": { "type": "string", "description": "Display name of the campaign." }, "description": { "type": "string", "maxLength": 1000, "description": "User-authored campaign brief, intended market, goals, and constraints." }, "status": { "type": "string", "enum": [ "active", "archived" ], "description": "Lifecycle state of the campaign." }, "audiences": { "type": "array", "description": "Audiences linked to this campaign — expanded on GET /v1/campaigns/{id}; empty array on list responses.\n", "items": { "type": "object", "properties": { "id": { "type": "string" }, "name": { "type": "string" }, "status": { "type": "string", "enum": [ "active", "archived", "expired" ] }, "record_count": { "type": [ "integer", "null" ] }, "segment_ids": { "type": "array", "items": { "type": "string" }, "description": "IDs of include-role segments in this audience." }, "excluded_segment_ids": { "type": "array", "items": { "type": "string" }, "description": "IDs of exclude-role segments in this audience." }, "segments": { "type": "array", "description": "Constituent segments; audiences can combine multiple subtypes.", "items": { "$ref": "#/$defs/ExpandedSegment" } }, "excluded_segments": { "type": "array", "description": "Expanded summaries of the exclude-role segments, same semantics as `segments`.", "items": { "$ref": "#/$defs/ExpandedSegment" } }, "set_logic": { "type": "string", "enum": [ "union", "intersection" ] }, "snapshot_version": { "type": "integer" }, "parent_audience_id": { "type": [ "string", "null" ] }, "linked_at": { "type": [ "string", "null" ], "format": "date-time", "description": "When this audience was linked to the campaign." } } } }, "created_at": { "type": "string", "format": "date-time" }, "updated_at": { "type": "string", "format": "date-time" } }, "$defs": { "ExpandedSegment": { "type": "object", "description": "Constituent segment summary and saved filter definition. Audiences may combine multiple segment subtypes; there is no primary segment or audience subtype.", "required": [ "id", "name", "record_count", "subtype", "input_record_count", "match_count" ], "properties": { "id": { "type": "string", "description": "Segment document ID." }, "name": { "type": "string", "description": "Segment display name." }, "record_count": { "type": [ "integer", "null" ], "description": "Cached record count of the segment. Null if never counted." }, "subtype": { "type": "string", "enum": [ "filter", "matched", "similarity", "propensity" ], "description": "Subtype of the constituent segment." }, "input_record_count": { "type": [ "integer", "null" ], "description": "matched subtype only. Count of records in the uploaded identity file. Null otherwise." }, "match_count": { "type": [ "integer", "null" ], "description": "matched subtype only. Count of records successfully matched. Null otherwise." }, "filter_groups": { "type": "array", "items": { "$ref": "#/$defs/FilterGroup" } }, "current_version": { "type": "integer" }, "record_limit": { "type": [ "integer", "null" ] } } }, "Filter": { "type": "object", "description": "A single filter condition for audience discovery or job execution", "required": [ "field", "op" ], "properties": { "field": { "type": "string", "description": "Canonical catalog field_name (e.g. age or state). ZIP5 also accepts zip, zip_code, or postal_code as input aliases; saved responses use zip5." }, "op": { "type": "string", "enum": [ "=", "!=", "<", "<=", ">", ">=", "IN", "NOT IN", "BETWEEN", "LIKE", "ARRAY_CONTAINS", "ARRAY_CONTAINS_ANY", "IS NULL", "IS NOT NULL" ], "description": "Comparison operator" }, "text_comparison": { "type": "string", "enum": [ "exact", "case_insensitive" ], "description": "Optional STRING comparison mode for =, !=, IN, NOT IN, and LIKE, or ARRAY membership mode for ARRAY_CONTAINS and ARRAY_CONTAINS_ANY. Defaults to exact. Case-insensitive mode applies Unicode case folding to both the stored value and the supplied value.\n" }, "trim_whitespace": { "type": "boolean", "description": "Optionally trim leading and trailing whitespace on both sides of a STRING or ARRAY comparison. Defaults to false; independent of text_comparison.\n" }, "value": { "oneOf": [ { "type": "string" }, { "type": "number" }, { "type": "boolean" }, { "type": "array", "items": { "oneOf": [ { "type": "string" }, { "type": "number" } ] } } ], "description": "The value to match against. For state, a published two-letter code or full State name is accepted and normalized to the code. Scalar types (`string`, `number`, `boolean`) are used for single-value operators (`=`, `!=`, `<`, `<=`, `>`, `>=`, `LIKE`, `ARRAY_CONTAINS`). Pass an **array** for `IN`, `NOT IN`, and `ARRAY_CONTAINS_ANY` — pass the array directly with no comma-encoding. `BETWEEN` takes a two-element array `[low, high]`. Omit entirely for `IS NULL` / `IS NOT NULL` checks.\n" } } }, "FilterGroup": { "type": "object", "description": "A group of Filter conditions. All `filters` within a single group are **always ANDed together** — there is no per-group intra-operator. The `combinator` attribute is an **inter-group** operator: it controls how this group is joined to the immediately preceding group in the array. The `combinator` on the first group (index 0) is always ignored.\n\nExample — `(city = \"NYC\" AND state = \"NY\") OR (state = \"CA\")`:\n```json [\n { \"id\": \"g1\", \"filters\": [{\"field\":\"city\",\"op\":\"=\",\"value\":\"NYC\"},\n {\"field\":\"state\",\"op\":\"=\",\"value\":\"NY\"}],\n \"combinator\": \"AND\" },\n { \"id\": \"g2\", \"filters\": [{\"field\":\"state\",\"op\":\"=\",\"value\":\"CA\"}],\n \"combinator\": \"OR\" }\n] ```\nGroup g1's `combinator` is irrelevant (it is the first group). Group g2's `combinator: \"OR\"` means the result is `(g1) OR (g2)`.\n", "required": [ "id", "filters", "combinator" ], "properties": { "id": { "type": "string", "description": "Stable identifier (UUID or NanoID). Used to track groups across edits.\n" }, "filters": { "type": "array", "items": { "$ref": "#/$defs/Filter" }, "description": "One or more filter conditions. All conditions in this array are combined with AND. Provide at least one filter per group.\n" }, "combinator": { "type": "string", "enum": [ "AND", "OR" ], "description": "**Inter-group operator.** Joins this group to the previous group in the array. `AND` narrows the result; `OR` broadens it. Ignored on the first group (index 0) — that group has no predecessor to join.\n" } } } } }