Contacts
Manage and organize your contacts effectively
Contacts in Plunk represent an individual email recipient. Each contact has an identifier and is linked to an email address.
Adding contacts
Contacts can be added to your Plunk project in several ways:
- Using
/v1/track— tracking an event for a contact that doesn't exist yet automatically creates it (subscribed by default). - Using
POST /contacts— create or upsert a single contact. Existing emails are updated, not rejected; the response includes a_meta: { isNew, isUpdate }block and uses status201for new contacts and200for updates. - Bulk CSV import via
POST /contacts/import— upload a CSV (≤ 5 MB) and pollGET /contacts/import/:jobIdfor status. The first column must beemail; any other columns map to keys underdata.*. - Bulk subscribe / unsubscribe / delete via
POST /contacts/bulk-subscribe,bulk-unsubscribe, andbulk-delete— each accepts up to 1,000 contact IDs and returns a job ID; pollGET /contacts/bulk/:jobIdfor progress. - Adding emails to a static segment with
POST /segments/:id/membersandcreateMissing: truewill create any contacts that don't already exist. - Manually through the dashboard.
Contact Data
You can associate custom data with each contact using key-value pairs. This data can be used for segmentation and personalization.
Data types
Contact data types are inferred from the first non-null value Plunk sees for a given key in your project:
| Type | Description |
|---|---|
| String | Any text value that doesn't look like a date. |
| Number | Numeric values, including integers and floats. |
| Boolean | true or false. |
| Date | A string matching YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS[.sss]Z. The full ISO 8601 form is required for date-aware operators in segments. |
The type is sampled per-project on first write — once a key is typed as number, subsequent string values for that key are still stored, but the inferred type stays number for the segment filter UI. If you accidentally mix types, the safest reset is to delete the field via DELETE /contacts/fields/:field and re-import with the type you want.
Default data type
If a value doesn't match number, boolean, or the ISO 8601 date format, it's typed as a string.
Non-persistent values
Send a value as { value, persistent: false } to use it once for template rendering without storing it on the contact:
{
"email": "user@example.com",
"data": {
"firstName": "Ada",
"resetCode": { "value": "ABC123", "persistent": false }
}
}firstName is saved on the contact; resetCode is available to the template for this send only and is then discarded. Use this for one-shot values like password reset codes, magic links, and one-time tokens.
Special value handling
When creating or updating contacts, certain values are handled specially:
| Value | Behavior | Example |
|---|---|---|
Empty string ("") | Ignored - field is not stored or updated | { name: "" } → Field is skipped |
null | Delete - field is removed from contact data | { name: null } → Field is deleted |
| Other values | Stored/updated normally | { name: "John" } → Stored as "John" |
Removing contact data
To remove a field from a contact's data, set it to null when creating or updating the contact. Empty strings are
automatically filtered out and won't overwrite existing data.
Reserved keys
Some keys are reserved by Plunk and managed at the contact level (not inside data). You can read them but you can't set them through data:
| Key | Description |
|---|---|
email | The contact's email address |
createdAt | Timestamp of when the contact was created |
updatedAt | Timestamp of the last update |
subscribed | Boolean indicating whether the contact is subscribed to marketing emails |
The following keys are also silently filtered out of any data payload — sending them through /v1/track, POST /contacts, or PATCH /contacts/:id will not store them and will not return an error:
id, plunk_id, plunk_email, unsubscribeUrl, subscribeUrl, manageUrl
The last three are auto-generated per-recipient at send time and exposed as template variables (see Templates).
Special keys
| Key | Description |
|---|---|
| locale | The contact's preferred locale in ISO 639 (e.g. 'en', 'fr', 'es'). Specifying the locale field on a contact will override the project-wide locale for contact-facing pages and email footers |
Subscription State
Every contact has a subscribed field that determines which types of emails they will receive. A newly created contact is subscribed by default when created via /v1/track; contacts created via POST /contacts use whatever value you pass (default: false).
When you update a contact, omitting subscribed keeps the current state — it is not the same as passing false. To change the state, pass an explicit true or false.
Every flip of subscribed automatically tracks an event on the contact:
subscribedflipped totrue→contact.subscribedeventsubscribedflipped tofalse→contact.unsubscribedevent
These events fire on every path that changes subscription state — manual edits, the public unsubscribe page, bulk operations, automatic unsubscribes from bounces / complaints. You can branch on them in workflows.
How contacts become unsubscribed
A contact can become unsubscribed in several ways:
- Manually through the dashboard or via the API.
- Self-service by clicking the unsubscribe link in an email (powered by the public unsubscribe pages).
- Automatically on a permanent (hard) email bounce. Soft bounces don't change subscription state.
- Automatically when a recipient marks one of your emails as spam (their mailbox provider reports the complaint back to Plunk).
Emails by subscription state
The subscription state controls whether a contact receives marketing emails. Transactional emails are always delivered regardless of subscription state.
| Email type | Subscribed | Unsubscribed |
|---|---|---|
| Transactional (via /v1/send) | Delivered | Delivered |
| Campaigns (marketing) | Delivered | Not delivered |
| Campaigns (headless) | Delivered | Not delivered |
| Campaigns (transactional) | Delivered | Delivered |
| Automations (marketing template) | Delivered | Not delivered |
| Automations (headless template) | Delivered | Not delivered |
| Automations (transactional template) | Delivered | Delivered |
Transactional emails and marketing templates
Even when using the transactional API endpoint (/v1/send), you cannot send a marketing template to an unsubscribed
contact. Use a transactional template instead if the email must reach unsubscribed contacts.