Sync your contacts
A contact sync has two parts. When a customer joins, you backfill the people your platform already holds for them, 500 at a time. After that, each change on your side is one upsert by your own id for the person. Both are idempotent, so a sync that runs twice does no harm. Do the backfill before the customer’s first campaign.
Before the first sync
Section titled “Before the first sync”- Create an attribute definition for each fact your templates and your customers’ campaigns will read: first name, plan, home site. Definitions belong to your platform, so this happens once, not per customer.
- Create the customer’s workspace, with your id for the customer as its
reference.
Backfill with the batch upsert
Section titled “Backfill with the batch upsert”Create or update contacts in a batch takes up to 500 contacts, each with its reference and the fields of a single upsert:
curl -X POST https://api.sendtruss.com/v1/workspaces/ref:cust_4821/contacts/batch \ -H "Authorization: Bearer $SENDTRUSS_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "contacts": [ { "reference": "guest_998", "email": "ana@example.com", "locale": "pt-BR", "attributes": {"first_name": "Ana"}, "marketing": {"state": "subscribed", "at": "2025-06-14T18:20:00Z"} }, { "reference": "guest_999", "email": "ben@example.com", "attributes": {"first_name": "Ben"} } ] }'Each contact is written or refused on its own, so one bad address doesn’t fail the other 499. The answer is always 200, with one result per contact in the order you sent them:
{ "data": [ {"reference": "guest_998", "result": "created", "id": "01JA2Q5D3B8C1E6F9G2H4J7K0M"}, { "reference": "guest_999", "result": "refused", "code": "email_taken", "message": "Another contact in this workspace has this email.", "contact": "ref:guest_412", "doc_url": "https://docs.sendtruss.com/errors/#email_taken" } ]}Check every result. A refused one carries the same code, message and doc_url a single upsert would have answered with, plus errors by field for validation_failed. Fix the data and send that contact again; sending the whole batch again is fine too, since contacts already written are just updated.
A batch counts as one request against your platform’s limit. Send batches one after another, not all at once, and on a 429 wait for the seconds in Retry-After.
What to send for consent
Section titled “What to send for consent”Send marketing only for people who actually agreed to marketing (or said no), with the time they did. Everyone else is created pending and gets no marketing, which is what you want for people whose consent you don’t know. Transactional email reaches them either way.
If your records hold an opt-out, send it as unsubscribed with its time. It protects the person from a later sync that still carries an older “yes”.
Keep in step with upserts
Section titled “Keep in step with upserts”After the backfill, call Create or update a contact whenever a person changes on your side, sending only the fields that changed:
curl -X PUT https://api.sendtruss.com/v1/workspaces/ref:cust_4821/contacts/ref:guest_998 \ -H "Authorization: Bearer $SENDTRUSS_API_KEY" \ -H "Content-Type: application/json" \ -d '{"email": "ana.souza@example.com"}'It answers 201 if the contact is new and 200 if it existed. Fields you leave out stay as they are, except tags, which, when you send it, is the contact’s whole set.
When the person agrees to marketing in your platform, send subscribed with the time. If it’s refused with consent_older_than_opt_out, the person left marketing after the time you sent. Don’t retry it: the newer choice wins, and the person rejoins through your own sign-up flow, which sends a fresh subscribed.
Listen for what people do in their inbox
Section titled “Listen for what people do in their inbox”Some changes start with the person, not with you: they leave marketing through the link in an email, or their address bounces. Register a webhook endpoint for contact.left_marketing, contact.rejoined_marketing and contact.suppressed, and update your own records when they arrive, so your platform shows the same state we hold. A sync shouldn’t send a consent back for these; we already have the person’s choice.
Removing people
Section titled “Removing people”When a person no longer belongs in the customer’s list, delete the contact:
curl -X DELETE https://api.sendtruss.com/v1/workspaces/ref:cust_4821/contacts/ref:guest_998 \ -H "Authorization: Bearer $SENDTRUSS_API_KEY"When they ask to be forgotten, erase them instead. See Privacy and erasure for the difference.
Checking what you synced
Section titled “Checking what you synced”List a workspace’s contacts, newest first, 50 to a page, filtered by marketing status, a tag’s key or part of the address:
curl "https://api.sendtruss.com/v1/workspaces/ref:cust_4821/contacts?status=subscribed" \ -H "Authorization: Bearer $SENDTRUSS_API_KEY"Follow links.next in each answer for the next page.