eusend
Audiences

Contact properties

Declare the custom fields your contacts carry, give them a type and a fallback value, and manage them from the API or the dashboard.

Contact properties are the custom fields your contacts carry — plan, company, renews_on — and the {{variables}} they render as in a broadcast. This page is about the definitions; setting a value on a contact is covered in Contacts.

Declaring a property is optional. A property you send on a contact that has never been declared registers itself as a string, so an existing integration needs no changes. Declaring one up front is what gives it a type and a fallback value.

Definitions belong to the organization, not to one audience: signup_plan means the same thing wherever the contact sits, so a contact moved between lists does not change shape.

Properties are also listed in the dashboard under Audiences → Properties, where the same add, edit and delete operations are available.

Fallback values

A declared property can carry a fallback, substituted into {{key}} for contacts that have no value of their own:

everyone without a plan reads as 'free'
curl -X POST https://api.eusend.dev/contact-properties \
  -H "Authorization: Bearer eu_live_xxxxxxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{ "key": "plan", "type": "string", "fallback_value": "free" }'

This is the durable version of the inline {{plan|free}} syntax: set it once and every broadcast picks it up, instead of each body having to remember the default. A property with no fallback renders empty, which is what an unset {{key}} has always done.

Types

string or number. Values are carried and rendered as strings either way — number is a write-time check, not a formatting instruction. A merge tag has nowhere to say which thousands separator or which locale it wanted, so {{order_total}} substitutes exactly the characters you sent. What the type buys is catching a mistyped value where it is cheap to fix, rather than in an email somebody already received.

POST/contact-properties
ParameterTypeDescription
keyrequiredstringLowercase letters, digits and underscores, starting with a letter, at most 40 characters. "email", "name", "first_name", "last_name" and "full_name" are built in and are rejected. Cannot be changed later.
typestring"string" (default) or "number". Cannot be changed later.
fallback_valuestring | nullRendered for contacts carrying no value of their own. Must match the type. At most 500 characters.

Returns 409 CONFLICT if a property with that name already exists. An organization can define up to 100 properties.

GET/contact-properties

Every property the organization has defined, ordered by name. Unpaginated — the registry is capped at 100 entries, and a variable picker wants all of them.

response
{
  "data": [
    {
      "id": "b6d24b8e-af0b-4c3c-be0c-359bbd97381e",
      "key": "plan",
      "type": "string",
      "fallbackValue": "free",
      "createdAt": "2026-09-21T10:14:52.110Z",
      "updatedAt": "2026-09-21T10:14:52.110Z"
    }
  ]
}
GET/contact-properties/:id

One property definition by id.

PATCH/contact-properties/:id
ParameterTypeDescription
fallback_valuerequiredstring | nullThe new fallback. Send null to clear it.

The name and type cannot be changed. Renaming would have to rewrite every contact and every broadcast body that spells the old merge tag — and we will not edit your drafts. Changing either is a delete and a create, done deliberately.

DELETE/contact-properties/:id

Deletes the definition and strips the key from every contact in the organization. The response reports how many contacts were rewritten:

response
{ "deleted": true, "contactsUpdated": 1240 }

This cannot be undone. Leaving the values behind was the alternative and a worse one: the property would keep rendering in broadcasts, and the next contact write carrying that key would register it again — so a delete you watched succeed would silently undo itself. Any broadcast using that merge tag renders it empty afterwards.

In the dashboard

Audiences → Properties lists every declared property with the number of contacts using it, and is where you add, edit and delete them. The count is what makes a delete legible: removing a field nothing uses is a different decision from removing one on 1,240 people.

SDKs

Node.js
await eusend.contactProperties.create({ key: 'plan', type: 'string', fallbackValue: 'free' })
const { data } = await eusend.contactProperties.list()
Python
eusend.ContactProperties.create({"key": "plan", "type": "string", "fallback_value": "free"})
properties = eusend.ContactProperties.list()
Go
fallback := "free"
client.ContactProperties.Create(&eusend.CreateContactPropertyRequest{
	Key:           "plan",
	Type:          "string",
	FallbackValue: &fallback,
})