Guides
Email series events
Tell Contacts that something happened to someone (a job paid, a quote sent) from your server or an n8n workflow, so the email series waiting for it start or stop.
An email series is a set of emails Contacts sends someone over time: a welcome run, a follow-up after a quote, a review request after a job. The owner builds them in the hub under Contacts, Email series, and many start when something happens: a quote is sent, a job is paid, a guide is downloaded.
Contacts can't see those things happen in your other systems. db.recordEvent() tells it.
import { createClient } from '@awesomate/sdk';
const db = createClient({ token: process.env.AWESOMATE_TOKEN! });
const { duplicate } = await db.recordEvent({
event: 'job_paid',
email: 'sam@example.com',
record: 'job-1042',
key: 'xero:INV-1042',
occurredAt: '2026-10-07T14:30:00+11:00',
});
// duplicate is true when this key was recorded beforeWhat happens
- Contacts decides who is in which series. The event says what happened. Any series waiting for that event starts for the person, and any series that stops on it stops. Your code never names a series.
- It never touches consent. The person is found by email, or added to Contacts (with
firstNameandlastNamewhen you give them), but an event can't sign anyone up for email. A series only emails people who may be emailed. - The same
keyis recorded once. Pass your own id for the event, such as the invoice number, so a retry or a webhook delivered twice does nothing the second time. recordnames the quote, job or booking it's about. A series that runs once per record keys on it.- An old event starts nothing. One more than two days old (by
occurredAt) is kept as a fact a series can read, never as a start, so replaying history can't email people about last month. - The answer is the same whether or not the address belongs to someone erased from Contacts.
Naming events
event is lower case: letters, digits and _ . : -, up to 64 characters. Use the past tense and the words the owner uses: quote_sent, job_paid, booked, guide_downloaded. The owner picks the same name when they set up the series.
Who can send them
recordEvent() needs the account's token (amt_pat_...) with crm:write, which tokens carry on Support Plus and above. An app's server key (ak_...) can't send events.
From n8n, post to the hub directly: POST https://hub.awesomate.ai/api/my-crm/v1/events with a Header Auth credential holding the token (Authorization: Bearer amt_pat_...) and a JSON body of event, email, and optionally record, occurred_at, key, first_name and last_name. It answers 202 with { "ok": true, "duplicate": false }.