Pre-launch API. The concepts described here are settled, but the API shape is not: request and response fields, parameters and defaults can still change. Build against it, and talk to your Luigi's Box contact before you put an integration into production.
const url = 'https://api.eu1.luigisbox.ai/platform/v1/campaigns/trigger-schema?page=1&size=20';const options = { method: 'POST', headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'}, body: '{"catalog_ids":["example"],"catalog_tags":["example"],"channel_ids":["example"],"channel_tags":["example"],"intents":["search"],"organization_id":"example","surface_ids":["example"],"surface_tags":["example"]}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url 'https://api.eu1.luigisbox.ai/platform/v1/campaigns/trigger-schema?page=1&size=20' \ --header 'Authorization: Bearer <token>' \ --header 'Content-Type: application/json' \ --data '{ "catalog_ids": [ "example" ], "catalog_tags": [ "example" ], "channel_ids": [ "example" ], "channel_tags": [ "example" ], "intents": [ "search" ], "organization_id": "example", "surface_ids": [ "example" ], "surface_tags": [ "example" ] }'Project the trigger fields authorable for a targeting set without persisting anything. Resolves the same effective scope a write would (422 on an invalid targeting set, problems in exception_details.problems), then returns, per unprefixed trigger field, the operators a write accepts for it across that whole scope. A field numeric in one scoped catalog but string (or absent) in another is reported with the string operator set, since that is what a write accepts for it. Each item carries its source (catalog attribute vs the request). The four request-owned fields (request:query, request:intent, request:type, request:anchor_id) are always included; add the trigger. prefix to a name to build a leaf. Items are sorted by name; query narrows to a case-insensitive substring on the name, and the result is paginated.
Authorizations
Section titled “Authorizations ”Parameters
Section titled “ Parameters ”Query Parameters
Section titled “Query Parameters ”Request Body required
Section titled “Request Body required ”A campaign’s targeting on its own — no name, no match, no rules, no persistence.
Ids are canonicalized, deduped and format-checked exactly as they are on a real
write, and every targeting violation is reported uniformly as a problems entry.
object
Surface Intents this campaign targets — the kind of discovery it applies to. Empty means every Intent, not none. Narrowing by Intent is mutually exclusive with narrowing by surface_ids / surface_tags: an Intent targets whole families of surfaces, so combining the two is rejected with intents_conflict. A targeted Intent no scoped catalog hosts a surface for is rejected with catalog_without_targeted_intent — it could never trigger.
Responses
Section titled “ Responses ”Successful Response
object
One trigger field authorable across a campaign’s scope.
name is the unprefixed field name (add trigger. to build a match
leaf). source is where the value comes from (catalog attribute vs the
request), and operators is the set a write accepts for the field anywhere
in the scope. values lists the literals the field admits and value_domain
says whether that list binds.
object
Unprefixed trigger field name. Add the trigger. prefix to build a match leaf — brand here is authored as trigger.brand.
Every operator a write accepts for this field anywhere in the scope. Range and comparison operators are offered on a numeric field; a keyword field offers membership operators only.
Where the value comes from when a campaign is matched: a catalog attribute of the matched anchor/collection document, or the request itself. Derived from the name — the reserved request: prefix cannot be occupied by catalog data.
How far values binds: closed is a fixed choice and anything else is rejected on save, suggested lists what the scope carries today while a value outside it is still accepted, and open is free input with values empty.
The literals this field admits, sorted. Populated only for request:-source fields, whose vocabularies are known here; a catalog attribute always reports [] because its values are catalog data, not schema — read those from GET /catalog/v1/{catalog_id}/types/{object_type}/attributes/{attribute_name}/values. An empty list never means the field accepts nothing.
Example
{ "items": [ { "operators": [ "eq" ], "source": "catalog", "value_domain": "closed" } ]}Missing or invalid credentials
Canonical error body — every non-2xx response uses this shape.
object
Machine-readable error context; empty object when there is nothing to add.
object
One field-level reason a request was rejected.
object
Path to the offending value from the request root, e.g. ["body", "filters", 0, "operator"].
What is wrong with the value at loc.
Stable machine code for the problem, e.g. missing or string_too_short.
Human-readable, actionable error message.
Example generated
{ "exception_details": { "validation_errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ] }, "reason": "example", "request_id": "example"}Authenticated but not permitted
Canonical error body — every non-2xx response uses this shape.
object
Machine-readable error context; empty object when there is nothing to add.
object
One field-level reason a request was rejected.
object
Path to the offending value from the request root, e.g. ["body", "filters", 0, "operator"].
What is wrong with the value at loc.
Stable machine code for the problem, e.g. missing or string_too_short.
Human-readable, actionable error message.
Example generated
{ "exception_details": { "validation_errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ] }, "reason": "example", "request_id": "example"}Request validation failed. A targeting rejection lists every problem at once in exception_details.problems.
The canonical error body of a rejected targeting set, with problems typed.
reason and request_id are the canonical fields; exception_details carries
the typed problems list.
object
The exception_details of a rejected targeting set: every problem found at once.
object
Every targeting violation found in one pass; never truncated.
One targeting violation: a stable machine code plus the offending values.
object
Stable machine code of the violated rule.
The targeting axis the violation is about.
Human-readable explanation of the violation.
The offending values on that axis.
Human-readable, actionable error message.
Canonical error body — every non-2xx response uses this shape.
object
Machine-readable error context; empty object when there is nothing to add.
object
One field-level reason a request was rejected.
object
Path to the offending value from the request root, e.g. ["body", "filters", 0, "operator"].
What is wrong with the value at loc.
Stable machine code for the problem, e.g. missing or string_too_short.
Human-readable, actionable error message.
Example
{ "exception_details": { "problems": [ { "code": "catalog_scope_required", "dimension": "catalog" } ] }}The catalog’s attribute types could not be read, so the request could not be type-checked; retryable.
Canonical error body — every non-2xx response uses this shape.
object
Machine-readable error context; empty object when there is nothing to add.
object
One field-level reason a request was rejected.
object
Path to the offending value from the request root, e.g. ["body", "filters", 0, "operator"].
What is wrong with the value at loc.
Stable machine code for the problem, e.g. missing or string_too_short.
Human-readable, actionable error message.
Example generated
{ "exception_details": { "validation_errors": [ { "loc": [ "example" ], "msg": "example", "type": "example" } ] }, "reason": "example", "request_id": "example"}Was this page helpful?
Thanks.