Contacts & events
The people you send to and the things they do.
Contacts
A contact is a person in a project, identified by email (and optionally
your own external_id). Contacts carry custom attributes — arbitrary
key/values you set — which you can reference in templates and filter on in
automations.
Upserts shallow-merge attributes: sending { "plan": "Pro" } updates plan
and leaves other attributes untouched.
curl https://sendandretain.com/api/v1/contacts \
-H "Authorization: Bearer $AEM_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "[email protected]", "attributes": { "plan": "Pro" } }'await fetch("https://sendandretain.com/api/v1/contacts", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AEM_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ email: "[email protected]", attributes: { plan: "Pro" } }),
});import os, requests
requests.post(
"https://sendandretain.com/api/v1/contacts",
headers={"Authorization": f"Bearer {os.environ['AEM_KEY']}"},
json={"email": "[email protected]", "attributes": {"plan": "Pro"}},
)A timezone attribute (IANA, e.g. America/New_York) controls automation send
windows for that contact.
Events
An event is something a contact did — order.completed, trial.started.
You emit events through the API; active automations whose trigger and filter
match enroll the contact synchronously.
curl https://sendandretain.com/api/v1/events \
-H "Authorization: Bearer $AEM_KEY" \
-H "Content-Type: application/json" \
-d '{ "email": "[email protected]", "name": "order.completed", "properties": { "total": 42.5 } }'await fetch("https://sendandretain.com/api/v1/events", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.AEM_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
email: "[email protected]",
name: "order.completed",
properties: { total: 42.5 },
}),
});import os, requests
requests.post(
"https://sendandretain.com/api/v1/events",
headers={"Authorization": f"Bearer {os.environ['AEM_KEY']}"},
json={"email": "[email protected]", "name": "order.completed", "properties": {"total": 42.5}},
)Emitting an event with an unknown email creates the contact. You can also pass
contact_attributes to upsert attributes in the same call, and a dedupe_key
to make the event idempotent.
Event properties and contact attributes are both available to automation
filters — that's how you target "trial started on the Pro plan".