Docs/API reference/Contacts

Contacts

Programmatic audience management. All endpoints are workspace-scoped through your API key, and emails are trimmed and lowercased before matching.

v1 · beta

Endpoints

EndpointMethodPurpose
/api/v1/contactsPOSTUpsert a contact by email
/api/v1/contacts?email=…GETFetch a contact with its tags
/api/v1/contacts/updatePOSTUpdate an existing contact (404 if missing)
/api/v1/contacts/deletePOSTDelete a contact (idempotent)
/api/v1/contacts/tags/addPOSTAttach a tag (auto-created, idempotent)
/api/v1/contacts/tags/removePOSTDetach a tag (idempotent)

Upsert a contact

bash
curl -X POST https://www.ewyn.ai/api/v1/contacts \
  -H "Authorization: Bearer $EWYN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "email": "user@example.com",
    "firstName": "Ada",
    "tags": ["customer", "beta"]
  }'

Body fields:

FieldTypeRequiredNotes
emailstringyesTrimmed and lowercased server-side
firstNamestringnoOverwrites the stored first name when provided
lastNamestringnoOverwrites the stored last name when provided
tagsstring[]noTag names to add — auto-created if missing; max 50 per call, 100 chars each

Response:

json
{
  "contact": {
    "id": "ct_...",
    "email": "user@example.com",
    "firstName": "Ada",
    "lastName": null,
    "tags": [{ "id": "tag_...", "name": "customer", "color": "#..." }]
  },
  "created": true,
  "suppressed": false
}

Tag operations

bash
# attach
curl -X POST https://www.ewyn.ai/api/v1/contacts/tags/add \
  -H "Authorization: Bearer $EWYN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "user@example.com", "tag": "vip" }'

# detach
curl -X POST https://www.ewyn.ai/api/v1/contacts/tags/remove \
  -H "Authorization: Bearer $EWYN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "email": "user@example.com", "tag": "beta" }'

tags/add returns the attached tag; tags/remove returns removed: false instead of failing when the tag wasn't attached. Both return 404 when the contact itself doesn't exist.

Semantics

  • Merge, never erase — upserts only overwrite the fields you provide; tags merge additively
  • Idempotent by design — deletes and tag-removals report deleted/removed: false rather than erroring, so retries are always safe
  • Tag names are case-sensitiveVIP and vip are different tags
Suppression is read-only here.

suppressed: true means the address unsubscribed, bounced, or complained. Contact data stays manageable, but send requests to that address are rejected with 422. There is no API to remove an address from the suppression list — that's deliberate.

Using TypeScript? The SDK contact methods wrap these endpoints one-to-one.

Was this page helpful?