Skip to content
Pneumail
Esc
↑↓navigate↵open⌘Jpreview
On this page

Contacts

What a contact's page shows, what can be changed there, and the API calls that read and edit the same record.

Every address in Contacts opens the contact’s page. So does each person in a campaign’s results, and Open contact in the preview’s subscriber picker.

What the page shows

Part What it holds
Header The address, first name and the day the contact was added
Suppressed Shown when no publication may email the address: why (bounced, marked as spam, unsubscribed everywhere, or by hand), where that came from, and when
Publications Each publication the contact is on: subscribed or not, how they joined (signed up, imported, or moved from another tool), the source and date of that consent, tags, and who ended the subscription
Fields first_name and every attribute, by the name a merge tag uses: city fills {{city}}
Emails The latest 50 emails sent to the contact, newest first, with what happened to each

Who ended a subscription is one of:

Value Meaning
link The unsubscribe link in an email, or the mailbox’s own unsubscribe button
import A CSV import or an API call marked them unsubscribed
profile:<address> Someone in the workspace, on the contact’s page
none The subscription ended before this was recorded

What happened to an email is the worst of what Amazon reported: rejected, marked as spam, bounced, unsubscribed through it, a temporary bounce, delivered, or sent and not reported yet. An email can also be queued, skipped (the person unsubscribed or was suppressed before their turn) or not sent. Test sends go to the people who write the campaign, so they are not listed. Opens and clicks are not tracked.

What can be changed

Admins and members can change these; contributors see the page but not the buttons.

  • Fields. Field names are lowercase letters, numbers and _, starting with a letter, up to 40 characters. Values are up to 200 characters; a contact has at most 100 fields. A saved field keeps its name, because campaigns may already use it; remove it and add a new one to rename it. If someone else saved the contact after you opened it, your save is refused so their change is not lost.
  • Unsubscribe from one publication. It cannot be undone from Pneumail: only the person can sign up again.
  • Suppress the address, so no publication in the workspace emails it. Suppressions are only added here.

Reading and editing a contact with the API

{contact} is the contact’s id (ct_...) or address. The id keeps the address out of request logs.

GET /api/v1/contacts/{contact}
Authorization: Bearer <key with contacts:read>
{
  "ok": true,
  "contact": {
    "id": "ct_...",
    "email": "ana@example.org",
    "firstName": "Ana",
    "attributes": { "city": "Tacoma", "seats": 3 },
    "createdAt": "2026-03-14T10:00:00.000Z",
    "version": "1792310400000000",
    "subs": [
      { "publicationId": "pub_...", "status": "unsubscribed", "consent": "signup", "source": "form:/updates",
        "consentedAt": "2026-03-14T10:00:00.000Z", "unsubscribedAt": "2026-10-02T09:00:00.000Z",
        "unsubscribedBy": "profile", "tags": ["resident"] }
    ],
    "suppression": null,
    "sends": [
      { "id": "snd_...", "kind": "campaign", "campaignId": "cmp_...", "subject": "October news", "publicationId": "pub_...",
        "status": "sent", "at": "2026-10-21T10:00:00.000Z", "deliveredAt": "2026-10-21T10:00:02.000Z", "bounce": null,
        "complainedAt": null, "unsubscribedAt": null, "rejected": false, "error": null }
    ],
    "moreSends": false
  }
}

The API says profile where the page names the person who unsubscribed someone, and Contact page for a suppression added there, so a key never learns who in the workspace did it.

PATCH /api/v1/contacts/{contact}
Authorization: Bearer <key with contacts:write>

{ "version": "1792310400000000", "firstName": "Ana", "attributes": { "city": "Tacoma", "seats": 4 } }

This replaces the first name and every field, with the same rules as the page: send the full set, and a field left out is removed. version comes from the last GET; if the contact changed since, the answer is 409 and nothing is saved. An unknown contact is 404.

To unsubscribe someone through the API, import them with status: "unsubscribed". To suppress an address, add it to /api/v1/suppressions.

Was this page helpful?