Attribute catalog¶
The attribute catalog lists the attributes an agent sends on its fetch requests, with the type, meaning, and coverage of each. Every agent (an application in the API) has its own catalog, so two agents in one org can send the same key with different meanings.
Rules depend on the catalog. Every attribute condition in a rule must name an entry in the catalog of the rule's agent, and the entry's type decides how the attribute's value is read when the rule is evaluated. See How attributes are read.
How entries arrive¶
An entry is created in one of three ways:
| Writer | How | Status |
|---|---|---|
| Fetch requests | Keys seen on the agent's fetch requests are added automatically, within about ten minutes. The type is inferred from the values sent. | observed |
| The agent platform | The team that runs the agent registers attributes with its API key, usually at integration time. See Register attributes. | documented |
| Marketers | Members of the org document attributes in the console, or through the Offer Manager API. | documented |
An entry can exist before the attribute arrives, so a rule can use an
attribute that the agent will start sending later. An entry stays in the
catalog when the agent stops sending the key, and lastSeenAt shows when it
last arrived. A marketer can set an entry to retired; rules can't use a
retired entry.
When both the platform and a marketer have written an entry, the platform's
type and values apply, and the marketer's label, description, and
examples are shown. The platform's own values stay in platform, so when a
marketer clears a field, the platform's value is shown again. writtenBy
records who wrote each shown field.
Entry fields¶
| Field | Type | Description |
|---|---|---|
_id |
string | The entry's ID. |
application |
string | The agent the entry belongs to. |
key |
string | The attribute key exactly as the agent sends it, 1 to 128 characters. Unique within the agent. |
type |
string | string, number, boolean, date, enum, or list. |
values |
array | For enum only, and required for it: the allowed values, as { value, label }. |
label |
string | The name marketers see, such as "Months at data limit in a row". |
description |
string | What the attribute means and how it is computed, for people and for the copilot. At most 2,000 characters. |
examples |
array | Up to 10 sample values. |
source |
string | Who supplies the attribute: agent, context_layer, or data_feed. |
status |
string | observed, documented, or retired. |
lastSeenAt |
string | When a request last carried the attribute, ISO 8601. Read-only. |
coverage |
number | The share of the agent's requests in the last seven days that carried the attribute, 0 to 1. Read-only. |
momentCoverage |
array | The same share per moment, as { moment, share, requests }, for each moment with requests in the last seven days. Read-only. |
channelCoverage |
array | The same share per channel, as { channel, share, requests }, for each channel (rcs, sms, webchat, messenger, voice) with requests in the last seven days. Requests that name no channel are left out. Read-only. |
platform |
object | The label, description, and examples the agent platform registered, when it registered any. Read-only. |
writtenBy |
object | Who wrote the shown type, label, description, examples, and values: observed, platform, or marketer. Read-only. |
A request carries an attribute when the key is present with a value. A key
sent as null or as an empty string doesn't count.
Types¶
The type decides how a value is read and which operators a condition can use:
| Type | Operators |
|---|---|
string, enum |
equals, not_equals, in, not_in, exists, not_exists |
number |
equals, not_equals, in, not_in, gt, gte, lt, lte, between, exists, not_exists |
boolean |
true, false, equals, not_equals, exists, not_exists |
date |
equals, not_equals, in, not_in, gt, gte, lt, lte, between, within_last, more_than_ago, exists, not_exists |
list |
contains, exists, not_exists |
For an enum, a condition's values must be among the entry's values.
An observed entry gets its type from the values seen: a key whose values are
all numbers, or strings that read as numbers, is a number; all true or
false is a boolean; all ISO 8601 dates is a date; all JSON arrays is a
list. Any other mix is a string. Register the attribute to set the type
you intend, especially for dates and enums.
Changing an entry's type, or deleting an entry, is refused with 409 when a
saved rule relies on it. The response names the rules. Change the rules
first, or retire the entry instead of deleting it.
Register attributes¶
The agent platform registers attributes with the API key it already uses for the Fetch API:
The key can also be sent as Authorization: Bearer <API_KEY>.
A key bound to an agent registers for that agent, and the body can omit
application. An org-wide key must name the agent in application. A
bound key that names a different agent returns 422 with reason
ApplicationMismatch.
Request body¶
| Field | Type | Description |
|---|---|---|
application |
string | The agent's ID. Required with an org-wide key. |
attributes |
array | 1 to 200 attributes, each with a unique key. |
Each attribute takes these fields:
| Field | Required | Description |
|---|---|---|
key |
Yes | The key as the agent sends it. |
type |
Yes | string, number, boolean, date, enum, or list. |
values |
For enum |
The allowed values, as { value, label }. |
label |
No | The name to show marketers. |
description |
No | What the attribute means and how it is computed. |
examples |
No | Up to 10 sample values. |
source |
No | agent (the default), context_layer, or data_feed. |
Registration creates the entries that don't exist and updates the ones that
do. It always updates platform, but never changes a shown field a marketer
wrote, other than type and values, and leaves a retired entry retired.
Registering the same attributes again is safe.
curl -X POST "https://ads.advertising.chat/v1/catalog/attributes?key=$API_KEY" \
-H "Content-Type: application/json" \
-d '{
"attributes": [
{
"key": "data_limit_streak_months",
"type": "number",
"label": "Months at data limit in a row",
"description": "Consecutive billing months in which the customer reached the plan data limit."
},
{
"key": "plan",
"type": "enum",
"values": [
{ "value": "prepaid_15", "label": "Prepaid 15 GB" },
{ "value": "unlimited", "label": "Unlimited" }
]
}
]
}'
Response¶
200 with the agent and its registered entries:
{
"application": "6512a9c4e1b2c3d4e5f60718",
"attributes": [
{
"_id": "6512b0f1e1b2c3d4e5f60801",
"application": "6512a9c4e1b2c3d4e5f60718",
"key": "data_limit_streak_months",
"type": "number",
"label": "Months at data limit in a row",
"source": "agent",
"status": "documented",
"platform": {
"label": "Months at data limit in a row",
"description": "Consecutive billing months in which the customer reached the plan data limit."
},
"writtenBy": { "type": "platform", "label": "platform", "description": "platform" }
}
]
}
List an agent's catalog¶
An org-wide key adds &application=<applicationId>. The response has the
same shape as a registration response, with every entry of the agent.
Errors¶
| Status | reason |
Cause |
|---|---|---|
401 |
The API key is missing or unknown. | |
422 |
InvalidAttributes |
The body failed validation. issues lists each problem as { path, message }. |
422 |
MissingRequiredParameter |
An org-wide key sent no application. |
422 |
UnknownApplication |
application isn't an agent in the key's org. |
422 |
ApplicationMismatch |
application differs from the agent the key is bound to. |
409 |
AttributeConflict |
A registration would change the type or values of an attribute that saved rules rely on. conflicts names them. Nothing is written. |
Channel coverage¶
The same requests also record which channel each one came from. Each moment's
_coverage field, read from the
Offer Manager API, holds the moment's requests over
the last seven days, the count per channel, and
unknown, the count that named no channel. A rule restricted to channels
matches none of the unknown requests, so a high unknown count means the
agent should send the channel parameter.