Skip to content

Audiences and contacts

An audience is a list of contacts you can send broadcasts to. A contact belongs to exactly one audience; the same email address in two audiences is two contacts, each with its own unsubscribe state.

Terminal window
curl -X POST https://api.spacepost.dev/audiences \
-H "Authorization: Bearer $SPACEPOST_API_KEY" -H "Content-Type: application/json" \
-d '{ "name": "Newsletter" }'
Response
{ "object": "audience", "id": "0192e1c4-0000-7000-8000-0000000000a1", "name": "Newsletter" }

GET /audiences, GET /audiences/{id} and DELETE /audiences/{id} complete the set. Deleting an audience deletes its contacts. Audience names are 1 to 100 characters.

Contacts live under their audience: /audiences/{audienceId}/contacts.

Create contact
emailstringrequired

Unique within the audience. Stored lower-cased. Creating a duplicate returns 422.

first_namestringoptional

Up to 100 characters. Used by {{{FIRST_NAME}}}.

last_namestringoptional

Up to 100 characters. Used by {{{LAST_NAME}}}.

unsubscribedbooleanoptional

Create the contact already unsubscribed (for example when importing a suppression list). Defaults to false.

contacts.ts
import { SpacePost } from "@spacepost/node";
const spacepost = new SpacePost(process.env.SPACEPOST_API_KEY);
const { data: audience, error } = await spacepost.audiences.create({ name: "Newsletter" });
if (error) throw new Error(error.message);
// Create
await spacepost.contacts.create({
audienceId: audience.id,
email: "ada@example.com",
firstName: "Ada",
lastName: "Lovelace",
});
// Read by email (or by id)
const { data: contact } = await spacepost.contacts.get({ audienceId: audience.id, email: "ada@example.com" });
console.log(contact?.unsubscribed);
// Update
await spacepost.contacts.update({ audienceId: audience.id, email: "ada@example.com", firstName: "Augusta" });
// List, newest first
const { data: page } = await spacepost.contacts.list({ audienceId: audience.id, limit: 50 });
console.log(page?.data.length, page?.has_more);
// Unsubscribe manually, then delete
await spacepost.contacts.update({ audienceId: audience.id, email: "ada@example.com", unsubscribed: true });
await spacepost.contacts.remove({ audienceId: audience.id, email: "ada@example.com" });
Terminal window
AUD=0192e1c4-0000-7000-8000-0000000000a1
# create
curl -X POST https://api.spacepost.dev/audiences/$AUD/contacts \
-H "Authorization: Bearer $SPACEPOST_API_KEY" -H "Content-Type: application/json" \
-d '{ "email": "ada@example.com", "first_name": "Ada", "last_name": "Lovelace" }'
# => { "object": "contact", "id": "..." }
# get by email (URL-encode the @) or by id
curl "https://api.spacepost.dev/audiences/$AUD/contacts/ada%40example.com" -H "Authorization: Bearer $SPACEPOST_API_KEY"
# update
curl -X PATCH "https://api.spacepost.dev/audiences/$AUD/contacts/ada%40example.com" \
-H "Authorization: Bearer $SPACEPOST_API_KEY" -H "Content-Type: application/json" \
-d '{ "unsubscribed": true }'
# delete
curl -X DELETE "https://api.spacepost.dev/audiences/$AUD/contacts/ada%40example.com" -H "Authorization: Bearer $SPACEPOST_API_KEY"

A contact looks like this:

{
"object": "contact",
"id": "0192e1c4-0000-7000-8000-0000000000c1",
"email": "ada@example.com",
"first_name": "Ada",
"last_name": "Lovelace",
"created_at": "2026-10-23T14:00:00.000Z",
"unsubscribed": false
}

DELETE returns { "object": "contact", "contact": "ada@example.com", "deleted": true }. Where an idOrEmail is expected you can pass either the contact id or the email address.

A contact with unsubscribed: true is skipped by every broadcast. Contacts unsubscribe themselves through the link in your emails (Unsubscribe), and you can set the flag through the API when you learn about an opt-out elsewhere.

Import with a loop, respecting the rate limit (10 requests per second on Free and Pro):

for (const row of rows) {
const { error } = await spacepost.contacts.create({ audienceId, email: row.email, firstName: row.first });
if (error?.name === "rate_limit_exceeded") await new Promise((r) => setTimeout(r, 1000));
}

Only import people who agreed to hear from you. See Compliance.