API Reference

Contacts API

Endpoints for managing email contacts and static list membership.

Lists vs consent
The lists field uses list slugs for segmentation only — it does not grant marketing consent. Use opt_in_subtype_slugs for consent. On contact responses, lists reflects static memberships only (not smart-list evaluation). See Contact Lists API.
POST/api/v1/contacts

Create a new contact or update an existing one (upsert by email). Use opt_in_subtype_slugs to grant marketing/operational subtype consent. See Subscriptions & Consent guide.

Request Body

FieldTypeRequiredDescription
emailstringYesContact email address
namestringNoContact name
dataobjectNoCustom data fields
custom_attributesobjectNoCustom contact attributes (dashboard-defined)
localestringNoContact locale (e.g. en, cs, en-US). Default: en. Not limited by dashboard supported locales
listsstring[]NoList slugs — append static memberships. Unknown or smart-list slugs return 400 with details.invalid_lists
opt_in_subtype_slugsstring[]NoGrant opt-in to these marketing/operational subtype slugs
double_opt_inbooleanNoSet false to skip DOI and confirm immediately (admin/import)
confirm_templatestringNoConfirm email template slug (default: consent-confirm). Success redirect URL is read from the template. See Double Opt-In Redirect guide.

Example Request

Terminal
curl -X POST https://artamail.artatol.net/api/v1/contacts \
-H "Authorization: Bearer am_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"name": "John Doe",
"locale": "en",
"data": { "plan": "premium" },
"opt_in_subtype_slugs": ["weekly-digest"],
"lists": ["customers"]
}'

Response

json
{
"id": "contact-uuid",
"email": "[email protected]",
"name": "John Doe",
"data": { "plan": "premium" },
"custom_attributes": {},
"locale": "en",
"subscribed": true,
"validation_status": "pending",
"lists": ["customers"],
"pending_confirmation": true,
"confirm_url": "https://artamail.artatol.net/api/confirm/...",
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"test_mode": false
}
Double opt-in
When org double opt-in is enabled, confirm_url is returned and pending_confirmation is true. You must send the confirm email (e.g. template consent-confirm) — ArtaMail does not auto-send it. Configure success redirect on the template. For multiple products, use one account per brand — see Multiple Products.
GET/api/v1/contacts/:email

Retrieve a contact by email address.

Example Request

Terminal
curl https://artamail.artatol.net/api/v1/contacts/user%40example.com \
-H "Authorization: Bearer am_live_sk_xxx"

Response

json
{
"id": "contact-uuid",
"email": "[email protected]",
"name": "John Doe",
"data": { "plan": "premium", "role": "admin" },
"subscribed": true,
"validation_status": "valid",
"locale": "en",
"lists": ["customers"],
"custom_attributes": {},
"created_at": "2024-01-15T10:30:00Z",
"updated_at": "2024-01-15T10:30:00Z",
"test_mode": false
}

Returns 404 if contact not found. lists contains static list slugs only.

PATCH/api/v1/contacts/:email

Update an existing contact.

Request Body

FieldTypeDescription
namestringContact name
dataobjectCustom data fields (merged with existing)
listsstring[]List slugs — append static memberships when provided. Unknown or smart-list slugs return 400 with details.invalid_lists. Omit the field to leave memberships unchanged; use POST .../lists to remove
custom_attributesobjectCustom attribute fields (merged with existing)
subscribedbooleanMaster subscription switch (blocks all marketing campaigns)
localestringContact locale

Example Request

Terminal
curl -X PATCH https://artamail.artatol.net/api/v1/contacts/user%40example.com \
-H "Authorization: Bearer am_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{ "name": "Jane Doe", "data": { "plan": "enterprise" } }'
POST/api/v1/contacts/:email/lists

Add and/or remove a contact from static lists by slug. Smart list slugs return a validation error — membership on smart lists is computed automatically.

Request Body

FieldTypeDescription
addstring[]List slugs to add the contact to
removestring[]List slugs to remove the contact from

Example Request

Terminal
curl -X POST https://artamail.artatol.net/api/v1/contacts/user%40example.com/lists \
-H "Authorization: Bearer am_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"add": ["vip", "newsletter"],
"remove": ["trial"]
}'

Response

json
{
"id": "contact-uuid",
"email": "[email protected]",
"name": "John Doe",
"lists": ["newsletter", "vip"],
"test_mode": false
}

Error response

json
{
"message": "Invalid or non-modifiable list slug(s)",
"code": "VALIDATION_ERROR",
"details": {
"invalid_lists": ["product-news-cs"]
}
}

invalid_lists includes unknown slugs and smart list slugs. See Contact Lists API.

DELETE/api/v1/contacts/:email

Permanently delete a contact when a user deletes their account in your app. Removes the contact profile, all subscription preferences, list memberships, and anonymizes stored email content. Cannot be undone — use POST /api/v1/contacts to add them again as a new contact.

Example Request

Terminal
curl -X DELETE https://artamail.artatol.net/api/v1/contacts/user%40example.com \
-H "Authorization: Bearer am_live_sk_xxx"

Returns 204 No Content on success. See also SDK deleteContact.

GET/api/v1/contacts/:email/subscription-preferences

Read per-subtype consent for a contact. See Subscription Types API.

PATCH/api/v1/contacts/:email/subscription-preferences

Update per-subtype consent from your app (API key). Partial update — send only changed keys. Consent is confirmed immediately (no double opt-in on this endpoint). Use type_slug/subtype_slug keys when subtype slugs are not unique per account.

Request Body

FieldTypeDescription
preferencesobjectMap of subtype key → subscribed boolean
unsubscribe_allbooleanOpt out all marketing and operational subtypes

Example Request

Terminal
curl -X PATCH https://artamail.artatol.net/api/v1/contacts/user%40example.com/subscription-preferences \
-H "Authorization: Bearer am_live_sk_xxx" \
-H "Content-Type: application/json" \
-d '{
"preferences": {
"newsletter/weekly-digest": true,
"newsletter/product-updates": false
}
}'
In-app vs email preference center
This endpoint uses your API key. Email-linked preference pages use GET/POST /api/u/{token}/... with a signed token instead — see Custom Preference URLs.

Validation Statuses

Contacts are automatically validated after creation:

StatusDescription
pendingAwaiting validation
validEmail address is valid
invalidEmail address is invalid (bounced, bad syntax, etc.)
riskyPotentially deliverable but flagged (disposable, role-based, etc.)
unknownValidation could not complete (e.g. DNS timeout)
Test Mode
With test API keys, contacts are not persisted. GET/PATCH/DELETE return 404. POST returns a simulated response with test_mode: true and includes confirm_url when opt-in would be pending.