---
title: Working with Contact Data
description: Use persistent and temporary contact data for personalized emails
---

## Contact Data Basics

Every contact has:
- **email**: Required, unique identifier
- **subscribed**: Boolean for subscription status
- **data**: JSON object for custom fields

```javascript
{
  "email": "user@example.com",
  "subscribed": true,
  "data": {
    "firstName": "Jane",
    "plan": "professional",
    "signupDate": "2024-03-15"
  }
}
```

## Persistent vs. Temporary Data

When sending emails, you can pass data that either saves to the contact or is used only for that email.

### Persistent Data (Default)

```javascript
fetch('/v1/send', {
  method: 'POST',
  body: JSON.stringify({
    to: 'user@example.com',
    subject: 'Welcome',
    body: '<p>Hi {'{{firstName}}'}!</p>',
    data: {
      firstName: 'John'  // Saved to contact.data.firstName
    }
  })
});
```

### Temporary Data (Non-Persistent)

```javascript
fetch('/v1/send', {
  method: 'POST',
  body: JSON.stringify({
    to: 'user@example.com',
    subject: 'Password Reset',
    body: '<p>Your code: {'{{resetCode}}'}</p>',
    data: {
      resetCode: {
        value: 'ABC123',
        persistent: false  // NOT saved to contact
      }
    }
  })
});
```

**Use temporary data for**:
- Password reset codes
- One-time verification tokens
- Session-specific information
- Temporary discount codes

## Template Variables

Use `{'{{fieldName}}'}` to insert contact data into emails.

### Basic Variables

```html
<p>Hello {'{{firstName}}'}!</p>
<p>Your plan: {'{{plan}}'}</p>
```

### Fallback Values

Provide defaults when data might be missing:

```html
<p>Hello {'{{firstName ?? \'there\'}}'}!</p>
<p>Plan: {'{{plan ?? \'Free\'}}'}</p>
```

### Reserved Fields

Two fields are always available:

```html
<p>Contact ID: {'{{plunk_id}}'}</p>
<p>Email: {'{{plunk_email}}'}</p>
```

## Data Merging

Updates merge with existing data:

```javascript
// Contact has: { firstName: 'John', plan: 'free' }

// Update with:
{ data: { lastName: 'Doe', plan: 'pro' } }

// Result: { firstName: 'John', lastName: 'Doe', plan: 'pro' }
```

## Best Practices

### Keep Data Flat

```javascript
// Good
{
  "firstName": "Jane",
  "plan": "pro",
  "mrr": 99
}

// Avoid nesting (harder to use in templates)
{
  "user": {
    "profile": {
      "name": "Jane"
    }
  }
}
```

### Use Consistent Naming

Pick a style and stick to it:

```javascript
// camelCase (recommended)
{ "firstName": "Jane", "lastLogin": "2024-03-15" }

// or snake_case
{ "first_name": "Jane", "last_login": "2024-03-15" }
```

### Store Dates as ISO Strings

```javascript
// Good (filterable, sortable)
{ "signupDate": "2024-03-15T10:30:00Z" }

// Avoid
{ "signupDate": "March 15, 2024" }
```

## Discovering Available Fields

Get all fields across your contacts:

```bash
curl -X GET "{{API_URL}}/contacts/fields" \
  -H "Authorization: Bearer sk_your_secret_key"
```

Response:
```json
{
  "success": true,
  "data": {
    "fields": [
      "email",
      "subscribed",
      "firstName",
      "plan",
      "signupDate"
    ],
    "count": 5
  }
}
```

Get unique values for a field:

```bash
curl -X GET "{{API_URL}}/contacts/fields/data.plan/values" \
  -H "Authorization: Bearer sk_your_secret_key"
```

Response:
```json
{
  "success": true,
  "data": {
    "field": "data.plan",
    "values": ["free", "professional", "enterprise"],
    "count": 3
  }
}
```

## Next Steps

- [Send personalized emails](/guides/templates)
- [Create segments](/guides/segments) based on contact data
- [Track events](/guides/events) to enrich contact profiles
