EnvlopedDocs

Contacts

API reference for managing marketing contacts (subscribers) with Envloped

Contacts

Contacts are the subscribers in your marketing audience. Every contact belongs to your account, carries a consent record, and has a lifecycle status. Contacts can be grouped into Lists for campaign targeting.

All endpoints require an Authorization: Bearer YOUR_API_KEY header.

The contact object

{
  "id": "ct_abc123",
  "email": "jane@example.com",
  "email_normalized": "jane@example.com",
  "first_name": "Jane",
  "last_name": "Doe",
  "attributes": { "plan": "pro" },
  "status": "subscribed",
  "consent_source": "api",
  "consent_at": "2026-01-15T10:30:00Z",
  "unsubscribed_at": null,
  "created_at": "2026-01-15T10:30:00Z",
  "updated_at": "2026-01-15T10:30:00Z"
}
FieldTypeDescription
idstringUnique contact identifier.
emailstringEmail address as provided.
email_normalizedstringNormalized address used for de-duplication and suppression cross-checks.
first_namestring | nullFirst name.
last_namestring | nullLast name.
attributesobjectArbitrary key/value data for merge tags and segmentation.
statusstringOne of subscribed, unsubscribed, bounced, complained, suppressed, pending.
consent_sourcestring | nullHow consent was captured: api, csv_import, form, manual.
consent_atstring | nullISO 8601 timestamp consent was recorded.
unsubscribed_atstring | nullISO 8601 timestamp of global opt-out, if any.
created_atstringISO 8601 creation timestamp.
updated_atstringISO 8601 last-update timestamp.

List contacts

GET /v1/contacts

Returns a paginated page of contacts.

Query parameters

ParameterTypeDescription
pagenumber1-based page number (default 1).
limitnumberPage size, 1–100 (default 50).
statusstringFilter by lifecycle status.
list_idstringRestrict to members of a given list.
searchstringCase-insensitive email substring match.

Response

{
  "contacts": [ /* contact objects */ ],
  "total": 1280,
  "page": 1,
  "totalPages": 26
}
curl "https://api.envloped.com/v1/contacts?status=subscribed&limit=50" \
  -H "Authorization: Bearer en_abc123..."

Create a contact

POST /v1/contacts

Creates a single contact and, optionally, adds it to lists. This is a strict create — a contact with the same normalized email already existing returns 409.

Request body

ParameterTypeRequiredDescription
emailstringYesEmail address.
first_namestringNoFirst name.
last_namestringNoLast name.
attributesobjectNoArbitrary attributes for merge tags / segmentation.
consent_sourcestringNoapi, csv_import, form, or manual (default api).
list_idsstring[]NoLists to add the new contact to. Unknown ids are reported in invalid_lists.

Consent is stamped at creation time (consent_at = now()), and the caller IP is recorded on the consent record.

Response — 201 Created

{
  "contact": { /* contact object */ },
  "added_to_lists": ["ls_newsletter"],
  "invalid_lists": []
}
curl -X POST https://api.envloped.com/v1/contacts \
  -H "Authorization: Bearer en_abc123..." \
  -H "Content-Type: application/json" \
  -d '{
    "email": "jane@example.com",
    "first_name": "Jane",
    "attributes": { "plan": "pro" },
    "list_ids": ["ls_newsletter"]
  }'

Errors

StatuserrorMeaning
400invalid_emailThe email failed validation.
409duplicate_contactA contact with this normalized email already exists.

Retrieve a contact

GET /v1/contacts/:id

Returns the contact plus its live list memberships.

{
  "contact": { /* contact object */ },
  "lists": [
    { "id": "ls_newsletter", "name": "Newsletter", "unsubscribed_at": null }
  ]
}

Returns 404 with { "error": "Contact not found" } if the id is unknown.

Update a contact

PATCH /v1/contacts/:id

Updates mutable fields. Only supplied fields change; attributes is replaced wholesale when provided. Setting status to unsubscribed stamps unsubscribed_at; moving to subscribed/pending clears it.

Request body

ParameterTypeDescription
first_namestring | nullNew first name (null clears it).
last_namestring | nullNew last name (null clears it).
attributesobjectReplacement attributes object.
statusstringNew lifecycle status.
curl -X PATCH https://api.envloped.com/v1/contacts/ct_abc123 \
  -H "Authorization: Bearer en_abc123..." \
  -H "Content-Type: application/json" \
  -d '{ "status": "unsubscribed" }'

Response: { "contact": { /* updated contact */ } }.

Delete a contact (GDPR erasure)

DELETE /v1/contacts/:id

Hard delete. The contact row is removed permanently and its list memberships are cascaded away. Campaign history is preserved with the contact reference nulled, so aggregate reports stay intact while the PII is gone. This is the endpoint to satisfy a right-to-erasure request.

{ "deleted": true, "id": "ct_abc123" }

Export contacts

GET /v1/contacts/export

Streams the full contact list as a CSV file (Content-Type: text/csv) with the columns email, first_name, last_name, status, consent_source, consent_at, unsubscribed_at, created_at. The export is keyset-paginated server-side so it stays memory-flat for very large audiences.

curl "https://api.envloped.com/v1/contacts/export" \
  -H "Authorization: Bearer en_abc123..." \
  -o contacts.csv

SDKs & CLI

The same operations are available in the official SDKs and CLI:

// JavaScript / TypeScript
await client.contacts.create({ email: 'jane@example.com', list_ids: ['ls_newsletter'] });
const { contacts } = await client.contacts.list({ status: 'subscribed' });
// Go
client.Contacts.Create(&envloped.CreateContactRequest{Email: "jane@example.com"})
# CLI
envloped contacts create jane@example.com --list ls_newsletter
envloped contacts list --status subscribed

On this page