Skip to content

Contacts

Manage your recipients with the Contacts API. Create, update, search, import via CSV, export, and organize contacts into segments for targeted broadcasts.

Per-topic preferences live under /subscription-topics/contacts/:contactId/subscriptions (see Subscription Topics); the dashboard's contact page shows every topic with a toggle. Contacts created through a signup form also get any submitted field that matches one of your contact properties.

POST
/contacts

Create a new contact. The email address must be unique within your account.

json
{
  "email": "alice@example.com",
  "first_name": "Alice",
  "last_name": "Smith",
  "properties": {
    "plan": "pro",
    "signed_up": "2026-01-15"
  },
  "unsubscribed": false
}
GET
/contacts

List contacts with pagination (per_page up to 100). Supports search by email or name, filtering by segment (segment_id, the seg_… public id), unsubscribed=true|false, and engagement_segment=active|at_risk|dormant.

json
{
  "data": [
    {
      "id": 9120,
      "publicId": "con_abc123def456ghi789",
      "email": "alice@example.com",
      "firstName": "Alice",
      "lastName": "Smith",
      "properties": { "plan": "pro" },
      "unsubscribed": false,
      "createdAt": "2026-03-23T10:00:00.000Z"
    }
  ],
  "meta": {
    "page": 1,
    "perPage": 20,
    "total": 1250,
    "totalPages": 63
  }
}
GET
/contacts/:id

Retrieve a single contact by ID, including all properties and subscription status.

json
{
  "contact": {
    "id": 9120,
    "publicId": "con_abc123def456ghi789",
    "email": "alice@example.com",
    "firstName": "Alice",
    "lastName": "Smith",
    "properties": {
      "plan": "pro",
      "signed_up": "2026-01-15"
    },
    "unsubscribed": false,
    "createdAt": "2026-03-23T10:00:00.000Z",
    "updatedAt": "2026-03-23T12:00:00.000Z"
  }
}
PATCH
/contacts/:id

Update a contact's details. Only provided fields are updated.

json
{
  "first_name": "Alice",
  "properties": {
    "plan": "enterprise",
    "upgraded_at": "2026-03-23"
  }
}
DELETE
/contacts/:id

Permanently delete a contact and remove them from all segments.

json
{
  "success": true
}
POST
/contacts/:id/unsubscribe

Unsubscribe a contact from all future emails. They will still exist in your contact list but will not receive broadcasts.

json
{
  "contact": {
    "id": 9120,
    "publicId": "con_abc123def456ghi789",
    "email": "alice@example.com",
    "unsubscribed": true,
    "updatedAt": "2026-03-23T15:00:00.000Z"
  }
}

Bulk Import

Import up to 10,000 contacts per request with POST /contacts/import. The body is JSON — a contacts array where each entry needs an email and may carry first_name, last_name and string-valued properties. Addresses that already exist are skipped, not updated — use PATCH /contacts/:id to change an existing contact. To import a CSV file, parse it on your side (or use the CSV upload in the dashboard) and send the rows. Limited to 10 requests per minute.

bash
curl -X POST https://api.poststack.dev/contacts/import \
  -H "Authorization: Bearer sk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "contacts": [
      { "email": "alice@example.com", "first_name": "Alice" },
      { "email": "bob@example.com", "properties": { "plan": "pro" } }
    ]
  }'
typescript
const result = await poststack.contacts.import({
  contacts: [
    { email: 'alice@example.com', first_name: 'Alice' },
    { email: 'bob@example.com', properties: { plan: 'pro' } },
  ],
});
// { imported: 2, skipped: 0, errors: [] }
// errors lists rows dropped for a property that failed validation.

Export

Export contacts as a CSV file. Pass segment_id (a segment's public id) to export only that segment's members — it works for both rule-based and manual segments. An unknown segment id returns 404 rather than falling back to the full list.

typescript
// Export all contacts
const csv = await poststack.contacts.exportCsv();
bash
# Whole list
curl "https://api.poststack.dev/contacts/export" \
  -H "Authorization: Bearer sk_live_..." \
  -o contacts.csv

# One segment
curl "https://api.poststack.dev/contacts/export?segment_id=seg_abc123def456" \
  -H "Authorization: Bearer sk_live_..." \
  -o eu-beta.csv

Custom Properties

Store arbitrary key-value data on contacts using the properties field. Property values can be used in template variables, segment rules, and workflow conditions:

typescript
const contact = await poststack.contacts.create({
  email: 'alice@example.com',
  first_name: 'Alice',
  properties: {
    plan: 'enterprise',
    company: 'Acme Inc',
    signup_source: 'website',
    lifetime_value: '4500',
  },
});

// Use properties in dynamic segments
await poststack.segments.create({
  name: 'Enterprise Users',
  rules: {
    operator: 'and',
    conditions: [
      { field: 'properties.plan', comparator: 'equals', value: 'enterprise' },
    ],
  },
});

Related

Contacts and audiences overviewManaging contacts, properties and consent in the dashboard.