Contact Properties

Define custom fields with specific types to store structured data on your subscribers. Properties let you go beyond free-form metadata with validated, typed fields like company name, plan tier, signup date, and more.

Overview

Contact properties are organization-level field definitions that can hold typed values per subscriber. Unlike the free-form metadata JSON field, properties have explicit types and validation.

TypeDescriptionExample
textFree-form text (max 10,000 chars)"Acme Inc"
numberNumeric value (integer or decimal)42, 3.14
dateISO 8601 date/datetime"2025-06-15T00:00:00Z"
booleanTrue or falsetrue, false
enumOne of a predefined set of options"starter", "pro", "enterprise"

Limits: Maximum 50 properties per organization. Property keys must start with a letter or underscore and contain only alphanumeric characters and underscores. Keys are unique per organization and cannot be changed after creation.

Create a Property

POST /v1/properties

Request Body

ParameterTypeDescription
keystringUnique key (required, max 64 chars, alphanumeric + underscore)
namestringDisplay name (required, max 128 chars)
typestringtext, number, date, boolean, or enum (default: text)
descriptionstringDescription (max 256 chars)
requiredbooleanWhether the property is required (default: false)
enumOptionsstring[]Options for enum type (required for enum, max 50 options)
sortOrdernumberDisplay order (default: 0)

Example

// Text property
const company = await client.properties.create({
  key: 'company',
  name: 'Company',
  type: 'text',
  description: 'The subscriber\'s company name',
});

// Enum property with predefined options
const plan = await client.properties.create({
  key: 'plan_tier',
  name: 'Plan Tier',
  type: 'enum',
  enumOptions: ['starter', 'pro', 'enterprise'],
  required: true,
});

// Boolean property
await client.properties.create({
  key: 'marketing_consent',
  name: 'Marketing Consent',
  type: 'boolean',
});

// Date property
await client.properties.create({
  key: 'trial_ends_at',
  name: 'Trial End Date',
  type: 'date',
});

List Properties

GET /v1/properties

Query Parameters

ParameterTypeDescription
activebooleanFilter by active status
const { data: properties } = await client.properties.list();
// [{ id, key, name, type, description, required, enumOptions, active, ... }]

// List only active properties
const { data: active } = await client.properties.list({ active: true });

Update & Delete Properties

PATCH /v1/properties/:id
DELETE /v1/properties/:id

You can update the display name, description, required flag, and enum options. The key and type cannot be changed after creation. Deleting performs a soft delete (sets active: false), preserving existing data.

// Update a property
await client.properties.update('prop_xxx', {
  name: 'Organization',
  description: 'Updated description',
});

// Add enum options
await client.properties.update('prop_xxx', {
  enumOptions: ['starter', 'pro', 'enterprise', 'custom'],
});

// Deactivate a property (soft delete)
await client.properties.delete('prop_xxx');

// Reactivate a property
await client.properties.update('prop_xxx', { active: true });

Subscriber Property Values

Set and retrieve property values for individual subscribers.

GET /v1/audiences/:audienceId/subscribers/:subscriberId/properties
PUT /v1/audiences/:audienceId/subscribers/:subscriberId/properties

Get Values

const { data: values } = await client.properties.getValues(
  'aud_xxx',
  'sub_xxx'
);

// {
//   company: { value: 'Acme Inc', type: 'text', name: 'Company' },
//   plan_tier: { value: 'enterprise', type: 'enum', name: 'Plan Tier' },
// }

Set Values

Send a JSON object of property key-value pairs. Values are validated against the property type. Set a value to null to delete it.

// Set property values (merges with existing)
await client.properties.setValues('aud_xxx', 'sub_xxx', {
  company: 'Acme Inc',
  plan_tier: 'enterprise',
  marketing_consent: true,
  trial_ends_at: '2025-07-01T00:00:00Z',
});

// Delete a property value
await client.properties.setValues('aud_xxx', 'sub_xxx', {
  trial_ends_at: null,
});

Python SDK

import veilmail

client = veilmail.VeilMail("veil_live_xxxxx")

# Create a property
client.properties.create(
    key="company",
    name="Company",
    type="text",
)

# List properties
result = client.properties.list()

# Set subscriber values
client.properties.set_values(
    "aud_xxx",
    "sub_xxx",
    {"company": "Acme Inc", "plan_tier": "enterprise"},
)

# Get subscriber values
values = client.properties.get_values("aud_xxx", "sub_xxx")

Using Properties in Templates

Property values can be used as template variables in your emails. Reference them using the property key in double curly braces.

await client.emails.send({
  from: 'hello@yourdomain.com',
  to: 'user@example.com',
  subject: 'Welcome, {{company}}!',
  html: `
    <h1>Welcome to the {{plan_tier}} plan!</h1>
    <p>Your trial ends on {{trial_ends_at}}.</p>
  `,
  templateData: {
    company: 'Acme Inc',
    plan_tier: 'Enterprise',
    trial_ends_at: 'July 1, 2025',
  },
});

Required Scopes

EndpointScope
List / Get propertiesproperty:read
Create / Update / Delete propertiesproperty:write
Get subscriber property valuesaudience:read
Set subscriber property valuesaudience:write