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,
})