> ## Documentation Index
> Fetch the complete documentation index at: https://developers.benchmarkemail.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Manage contacts

# Manage Contacts

Create, read, update, and delete contacts in your Benchmark Email account using the API.

## Goal

By the end of this guide you will be able to perform full CRUD operations on contacts: retrieve your contact structure (to get field IDs), create new contacts, retrieve them individually, update their fields or status, and delete them.

## Prerequisites

* An API key with **`contacts:write`** scope (for full CRUD) or **`contacts:read`** scope (for read-only access)
* Your API base URL (found on the Settings > API Keys page)

## Steps

### 1. Fetch your contact structure

Before creating contacts, retrieve your contact structure to get the field IDs you will need. Every contact belongs to a contact structure, and field values are set by referencing each field's `_id`.

```bash theme={null}
curl https://api-us-west-2-c1.benchmarkemail.com/api/contact-structure \
  -H "X-API-Key: bme_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
```

**Response** (`200 OK`):

```json theme={null}
[
  {
    "_id": "64a1b2c3d4e5f6a7b8c9d0e1",
    "label": "Default Contacts",
    "keyName": "Email",
    "keyType": "email",
    "fields": [
      { "_id": "64a1b2c3d4e5f6a7b8c9d100", "label": "First Name", "dataType": "text", "predefinedField": "firstName" },
      { "_id": "64a1b2c3d4e5f6a7b8c9d101", "label": "Last Name", "dataType": "text", "predefinedField": "lastName" }
    ],
    "tags": [
      { "_id": "64a1b2c3d4e5f6a7b8c9d300", "label": "VIP" }
    ]
  }
]
```

Save the contact structure `_id` and the field `_id` values. You will use these when creating and updating contacts. See [Manage Custom Fields](./manage-custom-fields.md) for more details on contact structures.

### 2. Create a contact

Send a `POST` request with the contact's email address (`key`), the contact structure it belongs to, and optionally any custom field values and list assignments.

```bash theme={null}
curl -X POST https://api-us-west-2-c1.benchmarkemail.com/api/contact \
  -H "X-API-Key: bme_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "jane.smith@example.com",
    "contactStructureId": "64a1b2c3d4e5f6a7b8c9d0e1",
    "fields": [
      { "_id": "64a1b2c3d4e5f6a7b8c9d100", "value": "Jane" },
      { "_id": "64a1b2c3d4e5f6a7b8c9d101", "value": "Smith" }
    ],
    "lists": [
      { "_id": "64a1b2c3d4e5f6a7b8c9d200" }
    ]
  }'
```

**Response** (`200 OK`):

```json theme={null}
{
  "_id": "66f1a6e4698f1bca60424901",
  "key": "jane.smith@example.com",
  "contactStructureId": "64a1b2c3d4e5f6a7b8c9d0e1",
  "fields": [
    { "_id": "64a1b2c3d4e5f6a7b8c9d100", "value": "Jane" },
    { "_id": "64a1b2c3d4e5f6a7b8c9d101", "value": "Smith" }
  ],
  "lists": [
    { "_id": "64a1b2c3d4e5f6a7b8c9d200" }
  ],
  "tags": [],
  "status": {
    "primary": "active",
    "secondary": "confirmed"
  },
  "createdAt": "2026-03-28T14:30:00.000Z",
  "updatedAt": "2026-03-28T14:30:00.000Z"
}
```

**Key points:**

* `key` is the contact's email address (required)
* `contactStructureId` is required — it determines which custom fields are available
* `fields` uses the field `_id` from your contact structure (see Step 1)
* `lists` optionally assigns the contact to one or more lists at creation time

### 3. Get a contact by ID

Retrieve a single contact using its `_id`.

```bash theme={null}
curl https://api-us-west-2-c1.benchmarkemail.com/api/contact/66f1a6e4698f1bca60424901 \
  -H "X-API-Key: bme_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
```

**Response** (`200 OK`):

```json theme={null}
{
  "_id": "66f1a6e4698f1bca60424901",
  "key": "jane.smith@example.com",
  "contactStructureId": "64a1b2c3d4e5f6a7b8c9d0e1",
  "fields": [
    { "_id": "64a1b2c3d4e5f6a7b8c9d100", "value": "Jane" },
    { "_id": "64a1b2c3d4e5f6a7b8c9d101", "value": "Smith" }
  ],
  "lists": [
    { "_id": "64a1b2c3d4e5f6a7b8c9d200" }
  ],
  "tags": [],
  "status": {
    "primary": "active",
    "secondary": "confirmed"
  },
  "createdAt": "2026-03-28T14:30:00.000Z",
  "updatedAt": "2026-03-28T14:30:00.000Z"
}
```

### 4. Update a contact's status

Use `PATCH` to update a contact's status (e.g., to deactivate a contact):

```bash theme={null}
curl -X PATCH https://api-us-west-2-c1.benchmarkemail.com/api/contact/66f1a6e4698f1bca60424901 \
  -H "X-API-Key: bme_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "Content-Type: application/json" \
  -d '{
    "status": {
      "primary": "inactive"
    }
  }'
```

**Response** (`200 OK`):

```json theme={null}
{
  "_id": "66f1a6e4698f1bca60424901",
  "key": "jane.smith@example.com",
  "contactStructureId": "64a1b2c3d4e5f6a7b8c9d0e1",
  "fields": [
    { "_id": "64a1b2c3d4e5f6a7b8c9d100", "value": "Jane" },
    { "_id": "64a1b2c3d4e5f6a7b8c9d101", "value": "Smith" }
  ],
  "status": {
    "primary": "inactive"
  },
  "createdAt": "2026-03-28T14:30:00.000Z",
  "updatedAt": "2026-03-28T15:10:00.000Z"
}
```

**Note:** `PATCH` only accepts the `status` field. To update other fields (email, custom fields, lists, tags), use `PUT` with the complete contact object.

### 5. Replace a contact (full update)

Use `PUT` to replace all contact fields. This is a full replacement — include all fields you want to keep.

```bash theme={null}
curl -X PUT https://api-us-west-2-c1.benchmarkemail.com/api/contact/66f1a6e4698f1bca60424901 \
  -H "X-API-Key: bme_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6" \
  -H "Content-Type: application/json" \
  -d '{
    "key": "jane.smith@example.com",
    "status": {
      "primary": "active",
      "secondary": "confirmed"
    },
    "fields": [
      { "_id": "64a1b2c3d4e5f6a7b8c9d100", "value": "Jane" },
      { "_id": "64a1b2c3d4e5f6a7b8c9d101", "value": "Smith-Jones" }
    ],
    "lists": [
      { "_id": "64a1b2c3d4e5f6a7b8c9d200" },
      { "_id": "64a1b2c3d4e5f6a7b8c9d201" }
    ]
  }'
```

### 6. Delete a contact

```bash theme={null}
curl -X DELETE https://api-us-west-2-c1.benchmarkemail.com/api/contact/66f1a6e4698f1bca60424901 \
  -H "X-API-Key: bme_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
```

**Response** (`200 OK`): Returns the deleted contact object.

### 7. List all contacts

Retrieve all contacts for your account. This endpoint returns all matching contacts in a single response (no pagination). For large contact databases, use [Search Contacts](./search-contacts.md) instead, which supports pagination and filtering.

```bash theme={null}
curl https://api-us-west-2-c1.benchmarkemail.com/api/contact \
  -H "X-API-Key: bme_live_a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6"
```

**Response** (`200 OK`):

```json theme={null}
[
  {
    "_id": "66f1a6e4698f1bca60424901",
    "key": "jane.smith@example.com",
    "contactStructureId": "64a1b2c3d4e5f6a7b8c9d0e1",
    "fields": [
      { "_id": "64a1b2c3d4e5f6a7b8c9d100", "value": "Jane" },
      { "_id": "64a1b2c3d4e5f6a7b8c9d101", "value": "Smith" }
    ],
    "status": {
      "primary": "active",
      "secondary": "confirmed"
    },
    "createdAt": "2026-03-28T14:30:00.000Z",
    "updatedAt": "2026-03-28T14:30:00.000Z"
  }
]
```

## Common Errors

| Status | Error                            | Cause                                                                 | Fix                                                                                        |
| ------ | -------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| `401`  | `UnauthorizedError`              | Invalid, expired, or inactive API key                                 | Verify your key is correct and active in Settings > API Keys                               |
| `403`  | `ForbiddenError` — missing scope | Key lacks `contacts:write` scope                                      | Create a new key with `contacts:write` scope, or upgrade the existing key's scopes         |
| `400`  | `ValidationError`                | Missing required fields (e.g., `key`, `contactStructureId` on create) | Check the request body includes all required fields                                        |
| `400`  | `DuplicateFieldError`            | Duplicate email address within the same contact structure             | Use [Search Contacts](./search-contacts.md) to check for existing contacts before creating |
| `404`  | `RecordNotFound`                 | Contact ID does not exist                                             | Verify the contact ID; it may have been deleted                                            |
| `429`  | `TooManyRequestsError`           | Rate limit or monthly quota exceeded                                  | Wait for the `Retry-After` period and retry. See [Rate Limits](../rate-limits.md)          |

## Next Steps

* [Search Contacts](./search-contacts.md) — find contacts by email or custom field values
* [Manage Lists](./manage-lists.md) — organize contacts into lists
* [Manage Custom Fields](./manage-custom-fields.md) — define the fields available on your contacts
* [Migration from Legacy](./migration-from-legacy.md) — end-to-end workflow for importing your data
