Custom Fields
Custom fields let you store business-specific data on contacts — company name, subscription plan, lead source, contract renewal date, or anything else relevant to your workflow.
Unlike a free-form JSON blob, SendSeven custom fields are schema-defined and typed. You first create a field definition (with a key, a type, and optional validation rules), then set values for that field on individual contacts. This gives you type validation, dropdown options, segmentation support, and personalization variables.
Earlier versions of this guide described setting an arbitrary custom_fields JSON object directly on POST /contacts or PUT /contacts/{id}. That is no longer supported. The custom_fields body field is ignored on contact create/update. Custom field values are now managed through the dedicated endpoints documented below — most importantly POST /api/v1/contacts/{contact_id}/fields/{field_id}.
The Two-Step Model
- Define the field once (an admin/settings operation) —
POST /api/v1/custom-fields. This returns a field definition with anid. - Set a value per contact —
POST /api/v1/contacts/{contact_id}/fields/{field_id}.
You only define a field once; afterwards you set/read its value on as many contacts as you like.
Required Scopes
| Scope | Purpose |
|---|---|
settings:read | List / view custom field definitions |
settings:update | Create / update custom field definitions |
settings:admin | Delete (deactivate) a custom field definition |
contacts:read | Read custom field values on a contact |
contacts:update | Set custom field values on a contact |
Field Types
field_type | Description |
|---|---|
text | Free-form text |
number | Numeric values (integers and decimals) |
boolean | True / false |
date | Date only (YYYY-MM-DD) |
datetime | Date and time (ISO 8601) |
select | Single selection from options |
multiselect | Multiple selections from options |
email | Email address |
phone | Phone number |
url | Website URL |
location | Latitude / longitude |
collection | Array of values |
select and multiselect require an options array. After a field is created, its key and field_type are immutable to preserve data integrity.
Step 1 — Define a Custom Field
curl -X POST "https://api.sendseven.com/api/v1/custom-fields" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{
"name": "Company Size",
"key": "company_size",
"field_type": "select",
"description": "Number of employees",
"options": ["1-10", "11-50", "51-200", "201-500", "500+"],
"required": false,
"display_order": 0
}'
Request fields
| Field | Required | Notes |
|---|---|---|
name | yes | Display name (1–100 chars) |
key | yes | Internal key, snake_case, must match ^[a-z][a-z0-9_]*$ |
field_type | yes | One of the types above |
description | no | Help text (≤ 500 chars) |
options | for select/multiselect | Array of allowed string values |
required | no | Defaults to false |
default_value | no | Default for new contacts |
agent_visible | no | Visible to agents (default true) |
agent_editable | no | Editable by agents (default true) |
user_editable | no | Editable by the contact via self-service (default false) |
display_order | no | Lower numbers sort first (default 0) |
Response (201 Created) — note the id, which you use to set values:
{
"id": "cf-12345678-abcd-efgh-ijkl-mnopqrstuvwx",
"tenant_id": "tn-12345678-abcd-efgh-ijkl-mnopqrstuvwx",
"name": "Company Size",
"key": "company_size",
"field_type": "select",
"description": "Number of employees",
"options": ["1-10", "11-50", "51-200", "201-500", "500+"],
"required": false,
"default_value": null,
"agent_visible": true,
"agent_editable": true,
"user_editable": false,
"display_order": 0,
"is_active": true,
"created_at": "2026-01-15T10:30:00Z"
}
List, Get, Update, Delete Definitions
# List all definitions (paginated)
curl "https://api.sendseven.com/api/v1/custom-fields?page=1&page_size=20" \
-H "Authorization: Bearer s7_api_..."
# Get one definition
curl "https://api.sendseven.com/api/v1/custom-fields/cf-12345678" \
-H "Authorization: Bearer s7_api_..."
# Update a definition (key and field_type cannot change)
curl -X PUT "https://api.sendseven.com/api/v1/custom-fields/cf-12345678" \
-H "Authorization: Bearer s7_api_..." \
-H "Content-Type: application/json" \
-d '{"options": ["1-10", "11-50", "51-200", "201-1000", "1000+"]}'
# Delete (soft-delete / deactivate) a definition
curl -X DELETE "https://api.sendseven.com/api/v1/custom-fields/cf-12345678" \
-H "Authorization: Bearer s7_api_..."
Deleting a field definition deactivates it (soft delete) so existing data is preserved; inactive fields can no longer be assigned new values.
Step 2 — Set a Field Value on a Contact
Send the value to POST /api/v1/contacts/{contact_id}/fields/{field_id}. The body is a single value whose type must match the field's field_type (and, for select/multiselect, must be one of the defined options).
curl -X POST "https://api.sendseven.com/api/v1/contacts/contact_d4e5f6a7/fields/cf-12345678" \
-H "Authorization: Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00" \
-H "Content-Type: application/json" \
-d '{"value": "51-200"}'
Response
{ "success": true, "message": "Field value updated" }
Setting the value again on the same field overwrites the previous value. A 404 is returned if the contact or the field definition does not exist.
Read Custom Field Values
All values for a contact
curl "https://api.sendseven.com/api/v1/contacts/contact_d4e5f6a7/fields" \
-H "Authorization: Bearer s7_api_..."
{
"contact_id": "contact_d4e5f6a7",
"fields": [
{
"field_id": "cf-12345678",
"field_key": "company_size",
"field_name": "Company Size",
"field_type": "select",
"value": "51-200"
}
]
}
Embedded in the contact
GET /api/v1/contacts/{contact_id} also returns custom field values under a custom_fields object, keyed by field key:
{
"id": "contact_d4e5f6a7",
"name": "Sophie Martin",
"email": "[email protected]",
"custom_fields": {
"company_size": {
"field_definition_id": "cf-12345678",
"name": "Company Size",
"field_type": "select",
"value": "51-200"
}
}
}
This embedded custom_fields object is read-only. Writing it back on PUT /contacts/{id} has no effect — use POST /contacts/{id}/fields/{field_id} to change a value.
Python Example
import requests
BASE_URL = "https://api.sendseven.com/api/v1"
HEADERS = {
"Authorization": "Bearer s7_api_a1b2c3d4e5f6789012345678abcdef00",
"Content-Type": "application/json",
}
# 1. Define the field once (settings:update)
field = requests.post(
f"{BASE_URL}/custom-fields",
headers=HEADERS,
json={
"name": "Plan",
"key": "plan",
"field_type": "select",
"options": ["basic", "professional", "scale", "enterprise"],
},
).json()
field_id = field["id"]
# 2. Set the value on a contact (contacts:update)
contact_id = "contact_d4e5f6a7"
requests.post(
f"{BASE_URL}/contacts/{contact_id}/fields/{field_id}",
headers=HEADERS,
json={"value": "enterprise"},
)
# 3. Read all custom field values for the contact (contacts:read)
values = requests.get(
f"{BASE_URL}/contacts/{contact_id}/fields",
headers=HEADERS,
).json()
print(values["fields"])
Common Custom Field Patterns
key | field_type | Use Case |
|---|---|---|
company | text | CRM sync |
source | select | Lead tracking |
plan | select | Subscription tier |
preferred_language | text | Localization |
external_id | text | Third-party system mapping |
lifetime_value | number | Revenue tracking |
last_order_date | date | E-commerce integration |
is_reseller | boolean | Segmentation flag |
Next Steps
- Manage Contacts -- full contact CRUD operations
- Tags & Lists -- organize contacts with tags and lists
- Messaging Campaigns -- target contacts with campaigns