Ensure an attribute definition exists

Search Documentation

Search across all developer documentation

attributes

Ensure an attribute definition exists

PUT /v1/attributes/by-name/{name}
Auth required api.attributes.manage

Idempotent "make sure this attribute exists", keyed by the attribute's name — the call a declarative integration makes on every deploy. Returns 201 when it registered the definition and 200 when the stored one already matches. Safe to repeat.

It never edits. A name that exists with a different schema returns 409 attribute_exists_differs and the stored definition is left alone. That response carries attribute_id, content_hash, and differs (the list of fields that disagree), so the follow-up edit goes straight to PUT /v1/attributes/{id} with no need to page the registry to find it.

The restraint is deliberate: changing an attribute's type is a disruptive edit that raises a standing eval_warning on every Segment referencing it. An hourly provisioning loop must not be able to trigger that silently, so a real change stays an explicit, expected_content_hash guarded, previewable edit.

What is compared: type, enum_values, and — only when the body supplies it — description. An omitted description is not a claim that the attribute has none, so annotating a definition in the dashboard never breaks a caller's ensure loop. enum_values compare as a set; their stored order is presentational. For a derived attribute the comparison is the canonical formula.

A git-backed definition is read-only here (409 conflict) — the repo owns it. An invalid name or type returns 422 validation_failed.

Path parameters

name string required

The attribute name — a lowercase identifier, referenced in SendQL as attr.<name>.

Request body

Content type: application/json

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. Compared as a set — order is not part of the schema.

description string optional

Asserted only when supplied. Omitting it is not a claim that the attribute has no description, so a definition annotated in the dashboard will not start failing an ensure that never mentioned it.

formula string optional

Asserts a derived attribute (see V1AttributeWrite.formula). Compared in canonical form. A formula is immutable, so a stored definition whose formula differs is reported as diverging rather than converged.

Responses

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

200 The attribute already exists and matches; 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).

origin string enum optional

Where the attribute is authored: managed (via the API/dashboard) or git (synced from a connected repo and read-only via the API).

One of: managed, git

source_path string optional

Repo-relative source file, for git-backed attributes only.

last_synced_at string<date-time> optional

Time of the last git sync, for git-backed attributes only.

created_at string<date-time> required
updated_at string<date-time> required
201 The attribute was registered 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).

origin string enum optional

Where the attribute is authored: managed (via the API/dashboard) or git (synced from a connected repo and read-only via the API).

One of: managed, git

source_path string optional

Repo-relative source file, for git-backed attributes only.

last_synced_at string<date-time> optional

Time of the last git sync, for git-backed attributes only.

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 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 — or the name belongs to a git-backed definition, which is read-only here (code is conflict). Nothing was written in either case. application/problem+json
422 Query parameter or path value failed validation 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