Register a custom-attribute definition

Search Documentation

Search across all developer documentation

attributes

Register a custom-attribute definition

POST /v1/attributes
Auth required api.attributes.manage

Registers a new managed attribute definition — the typed schema a Segment's SendQL predicate can then reference as attr.<name>. enum_values is required when type is enum and rejected otherwise. An invalid name or type returns 422 validation_failed.

Safe to repeat. A name that is already registered does not fail merely for being taken:

Stored definition Response
absent 201 — the created definition
present and identical to the body 200 — the existing definition, nothing written
present with a different schema 409 attribute_exists_differs

The 409 attribute_exists_differs carries attribute_id, content_hash and differs, so the follow-up edit goes straight to PUT /v1/attributes/{id} without paging the registry.

This endpoint never edits. Convergence means it will agree that a matching definition exists; changing one stays an explicit, expected_content_hash guarded, previewable edit, because a type change is disruptive and raises a standing eval_warning on every Segment referencing the attribute.

What is compared is the same basis the by-name ensure uses: type, enum_values (as a set — their stored order is presentational) and, only when the body supplies a non-empty one, description. A blank or omitted description is not a claim that the attribute has none, so annotating a definition in the dashboard never breaks a provisioning loop. For a derived attribute the comparison is the canonical formula.

PUT /v1/attributes/by-name/{name} expresses the same intent more directly, and is the better call for a declarative integration: the name lives in the path, so there is no create-shaped body to send for something that already exists.

Request body

Content type: application/json

name string required

Lowercase identifier (letters, digits, underscore), referenced in SendQL as attr.<name>.

type string enum optional

Required for an ordinary attribute; ignored when formula is set (the derived type is inferred).

One of: string, number, bool, datetime, enum

enum_values array<string> optional

Required when type is enum; must be empty/omitted otherwise.

description string optional
formula string optional

Creates a derived attribute (SND-1067) whose value SendOps computes and maintains from the contact's event/activity stream. One aggregate over one source: exists, count, first, or last of a SES event name (send, open, click, …) or activity.<name> — e.g. exists(send), count(activity.order). The value type is inferred; type/enum_values are ignored. Derived attributes are managed-only (not promotable) and their formula is immutable (change = delete + recreate). Create-only.

Responses

Errors follow the RFC 7807 problem format — see the error reference.

200 The attribute already exists and matches the body; nothing was written application/json
id string<uuid> required
name string required

Lowercase identifier; referenced in SendQL as attr.<name>.

type string enum required

One of: string, number, bool, datetime, enum

enum_values array<string> optional

Allowed values when type is enum; omitted otherwise.

description string required
formula string optional

For a derived attribute (SND-1067): the aggregate expression SendOps computes over the contact's event/activity stream, e.g. exists(send), count(activity.order), last(open). Present only for derived attributes; their value is maintained by SendOps (read-only) and type is inferred (exists→bool, count→number, first/last→datetime).

created_at string<date-time> required
updated_at string<date-time> required
201 The created attribute definition application/json
id string<uuid> required
name string required

Lowercase identifier; referenced in SendQL as attr.<name>.

type string enum required

One of: string, number, bool, datetime, enum

enum_values array<string> optional

Allowed values when type is enum; omitted otherwise.

description string required
formula string optional

For a derived attribute (SND-1067): the aggregate expression SendOps computes over the contact's event/activity stream, e.g. exists(send), count(activity.order), last(open). Present only for derived attributes; their value is maintained by SendOps (read-only) and type is inferred (exists→bool, count→number, first/last→datetime).

created_at string<date-time> required
updated_at string<date-time> required
401 Missing, malformed, or unknown API key application/problem+json
403 Key lacks the required scope or plan limit violated application/problem+json
409 Returned by POST /v1/attributes and PUT /v1/attributes/by-name/{name}. Either the attribute exists with a schema other than the one asserted — code is attribute_exists_differs, and the body carries attribute_id, content_hash and differs so the edit can be made without searching for the definition. Nothing was written. application/problem+json
422 A query parameter, path value or body field failed validation. The body is a validation_failed Problem. When the refusal is about a reference — a segment key, template slug, topic or attribute name the organization does not have — it additionally carries validation_code, field, line/column, missing, candidates and next_step, so a client can correct the call without a second round of guessing. See ValidationProblem. application/problem+json
429 Per-org rate limit exceeded application/problem+json
500 Unexpected server-side failure. The code is internal_error. The request_id field can be quoted to SendOps support to investigate. application/problem+json