Update wiki
This commit is contained in:
@@ -0,0 +1,214 @@
|
||||
---
|
||||
title: Contacts and Data
|
||||
description: Store and manage your audience
|
||||
icon: Users
|
||||
---
|
||||
|
||||
## What are contacts
|
||||
|
||||
Contacts are people in your email list. Each contact has:
|
||||
|
||||
- **Email** — Unique identifier
|
||||
- **Subscription status** — Subscribed or unsubscribed
|
||||
- **Custom data** — Any fields you need
|
||||
|
||||
## Data structure
|
||||
|
||||
```json
|
||||
{
|
||||
"id": "contact_abc123",
|
||||
"email": "[email protected]",
|
||||
"subscribed": true,
|
||||
"data": {
|
||||
"firstName": "Sarah",
|
||||
"plan": "pro",
|
||||
"mrr": 99
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `data` field stores custom information as key-value pairs.
|
||||
|
||||
## Data types
|
||||
|
||||
**Strings:**
|
||||
```json
|
||||
{ "firstName": "Sarah", "company": "Acme Inc" }
|
||||
```
|
||||
|
||||
**Numbers:**
|
||||
```json
|
||||
{ "mrr": 99, "loginCount": 15 }
|
||||
```
|
||||
|
||||
Store as numbers for `greaterThan`/`lessThan` comparisons.
|
||||
|
||||
**Booleans:**
|
||||
```json
|
||||
{ "verified": true, "newsletter": false }
|
||||
```
|
||||
|
||||
**Dates:**
|
||||
```json
|
||||
{ "signupDate": "2024-03-15T10:30:00Z" }
|
||||
```
|
||||
|
||||
Use ISO 8601 format.
|
||||
|
||||
**Arrays:**
|
||||
```json
|
||||
{ "tags": ["vip", "enterprise"] }
|
||||
```
|
||||
|
||||
**Objects:**
|
||||
```json
|
||||
{
|
||||
"address": {
|
||||
"city": "San Francisco",
|
||||
"country": "US"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Access nested fields: `address.country`
|
||||
|
||||
## Creating contacts
|
||||
|
||||
### Via API
|
||||
|
||||
```bash
|
||||
curl -X POST {{API_URL}}/contacts \
|
||||
-H "Authorization: Bearer sk_your_secret_key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "[email protected]",
|
||||
"subscribed": true,
|
||||
"data": {
|
||||
"firstName": "Sarah",
|
||||
"plan": "pro"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
### Automatic upsert
|
||||
|
||||
If email exists, updates instead of creating duplicate.
|
||||
|
||||
```javascript
|
||||
// First call
|
||||
POST /contacts { email: "[email protected]", data: { plan: "free" } }
|
||||
|
||||
// Second call - updates same contact
|
||||
POST /contacts { email: "[email protected]", data: { mrr: 99 } }
|
||||
|
||||
// Result: { plan: "free", mrr: 99 }
|
||||
```
|
||||
|
||||
Data merges automatically.
|
||||
|
||||
### Via event tracking
|
||||
|
||||
```bash
|
||||
curl -X POST {{API_URL}}/v1/track \
|
||||
-H "Authorization: Bearer pk_your_public_key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"email": "[email protected]",
|
||||
"event": "signed_up",
|
||||
"data": {
|
||||
"plan": "pro",
|
||||
"source": "landing"
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
Creates contact if doesn't exist, updates if does.
|
||||
|
||||
## Updating contacts
|
||||
|
||||
```bash
|
||||
curl -X PATCH {{API_URL}}/contacts/contact_id \
|
||||
-H "Authorization: Bearer sk_your_secret_key" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{
|
||||
"data": {
|
||||
"plan": "premium",
|
||||
"mrr": 199
|
||||
}
|
||||
}'
|
||||
```
|
||||
|
||||
New fields added, existing fields overwritten, unmentioned fields preserved.
|
||||
|
||||
### Remove fields
|
||||
|
||||
Set to `null`:
|
||||
|
||||
```json
|
||||
{ "data": { "temporaryToken": null } }
|
||||
```
|
||||
|
||||
## Subscription status
|
||||
|
||||
**Subscribed (true):**
|
||||
- Receives marketing emails
|
||||
- Receives transactional emails
|
||||
|
||||
**Unsubscribed (false):**
|
||||
- Does NOT receive marketing emails
|
||||
- Still receives transactional emails
|
||||
|
||||
Template type controls this behavior. See [Template Types](/concepts/templates-types).
|
||||
|
||||
## Using contact data
|
||||
|
||||
### In templates
|
||||
|
||||
```html
|
||||
<h1>Hi {{firstName}}!</h1>
|
||||
<p>Your {{plan}} plan renews on {{renewalDate}}.</p>
|
||||
```
|
||||
|
||||
### In segments
|
||||
|
||||
Filter by data fields:
|
||||
- `plan equals "premium"`
|
||||
- `mrr greaterThan 100`
|
||||
- `loginCount lessThan 5`
|
||||
|
||||
### In workflows
|
||||
|
||||
```
|
||||
[Condition: plan equals "enterprise"]
|
||||
├─ True → [Send: Enterprise content]
|
||||
└─ False → [Send: Standard content]
|
||||
```
|
||||
|
||||
## Best practices
|
||||
|
||||
**Consistent naming** — Use camelCase or snake_case, not both.
|
||||
|
||||
**Correct types** — Use `99` not `"99"` for numbers.
|
||||
|
||||
**ISO dates** — `"2024-03-15T10:30:00Z"` for date fields.
|
||||
|
||||
**Sync critical fields only** — Don't mirror entire database. Only fields used in emails, segments, or workflows.
|
||||
|
||||
**Update in real-time** — When user data changes, update contact immediately.
|
||||
|
||||
**Respect unsubscribes** — Never re-subscribe automatically.
|
||||
|
||||
## Deleting contacts
|
||||
|
||||
```bash
|
||||
curl -X DELETE {{API_URL}}/contacts/contact_id \
|
||||
-H "Authorization: Bearer sk_your_secret_key"
|
||||
```
|
||||
|
||||
Permanent deletion. Consider unsubscribing instead to preserve history.
|
||||
|
||||
## Next steps
|
||||
|
||||
- [Create segments](/concepts/segments-and-filters)
|
||||
- [Track events](/concepts/events-and-triggers)
|
||||
- [Use templates](/concepts/templates-types)
|
||||
Reference in New Issue
Block a user