# Contacts

Creates or updates a contact in Retainful. If a contact with a matching identifier already exists (such as the same email), that contact is updated. Otherwise, a new contact is created. Email identifier is required to create a contact.

### Endpoint

*POST /v2/contacts*

\
**Authentication**\
You must include your App ID and the API key in the request headers.

Example header:

```
Retainful-Api-Key: <Your API Key>
Retainful-App-Id: <Your App ID>
```

### Request Body

| Field                 | Required? | Type            | Description                                                                                                                                           |
| --------------------- | --------- | --------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `firstName`           | Yes       | string          | Contact’s first name.                                                                                                                                 |
| `lastName`            | No        | string          | Contact’s last name.                                                                                                                                  |
| `birthDate`           | No        | string (date)   | Date of birth in [ISO 8601](https://en.wikipedia.org/wiki/ISO_8601) format.                                                                           |
| `city`                | No        | string          | City of residence.                                                                                                                                    |
| `countryCode`         | No        | string          | Two-letter country code (e.g., `US`, `CA`).                                                                                                           |
| `country`             | No        | string          | Full country name (e.g., `United States`).                                                                                                            |
| `provinceCode`        | No        | string          | Province or state code (e.g., `CA` for California).                                                                                                   |
| `state`               | No        | string          | Full state or province name (e.g., `California`).                                                                                                     |
| `postalCode`          | No        | string          | ZIP or postal code.                                                                                                                                   |
| `gender`              | No        | string          | Gender of the contact (`m`, `f`, etc.).                                                                                                               |
| `createdAt`           | No        | string (date)   | Contact creation date. If omitted, the current time will be used.                                                                                     |
| `triggerWelcomeEmail` | No        | boolean         | If `true`, triggers a welcome email flow (if configured). Default is `false`.                                                                         |
| `listIds`             | Yes       | array of string | Array of list IDs to which the contact will be subscribed.                                                                                            |
| `identifiers`         | Yes       | array of object | **Required.** An array that defines how to identify this contact (email, phone, etc.). See [table below](#identifiers-object) for detailed structure. |

### Identifiers Object

Each item in the `identifiers` array describes a unique identifier (such as an email or phone number) and includes the subscription status and consent details.

| Field      | Type             | Required? | Description                                                                                                                                                     |
| ---------- | ---------------- | --------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`     | string           | Yes       | <p>Type of identifier (e.g., <code>email</code>, <code>phone</code>). Accepted values: <br>email<br>phone</p>                                                   |
| `id`       | string or number | Yes       | The actual identifier (e.g., the email address or phone number).                                                                                                |
| `channels` | object           | Yes       | <p>An object with channel-specific statuses. E.g., <code>{ "email": { "status": "subscribed" } }</code>.<br><br>See Ch<a href="#channels">annels object</a></p> |
| `consent`  | object           | Yes       | Contains details about when, how, and where consent was granted.  See [Consent object ](#consent)                                                               |

### **Channels**

The `channels` object tracks subscription statuses for each communication channel. For example:

```json
{
  "channels": {
    "email": {
      "status": "subscribed"
    },
    "phone": {
      "status": "unsubscribed"
    }
  }
}
```

| Channel Key | Value              | Required?               | Description                                                                                       |
| ----------- | ------------------ | ----------------------- | ------------------------------------------------------------------------------------------------- |
| `email`     | object (see below) | Yes (if no phone given) | Subscription status for email channel. Example: `"status": "subscribed"` or `"unsubscribed"`.     |
| `phone`     | object (see below) | Yes (if no email given) | Subscription status for phone/SMS channel. Example: `"status": "subscribed"` or `"unsubscribed"`. |

Within each channel’s object, the most common field is:

* **`status`**: string. Represents the subscription status. Typical values: `subscribed`, `unsubscribed`

### **Consent**

The `consent` object captures how and when the contact gave permission for communication.

```json
{
  "consent": {
    "createdAt": "2024-03-21T10:30:00.000Z",
    "ip": "192.168.1.1",
    "source": "web_form"
  }
}
```

| Field       | Type          | Required? | Description                                                                                        |
| ----------- | ------------- | --------- | -------------------------------------------------------------------------------------------------- |
| `createdAt` | string (date) | Yes       | Date-time (in ISO 8601 format) when the contact gave consent (e.g., `"2024-03-21T10:30:00.000Z"`). |
| `ip`        | string        | Yes       | IP address from which the contact provided consent.                                                |
| `source`    | string        | Yes       | Source through which consent was provided (e.g., `web_form`, `import`, etc.).                      |

### Example Request

```json
POST /v2/contacts
Retainful-Api-Key: YOUR_API_KEY
Retainful-App-Id: YOUR_APP_ID
Content-Type: application/json

{
  "firstName": "John",
  "lastName": "Doe",
  "birthDate": "1990-01-15T00:00:00.000Z",
  "city": "San Francisco",
  "countryCode": "US",
  "country": "United States",
  "provinceCode": "CA",
  "createdAt": "2024-03-21T10:30:00.000Z",
  "gender": "m",
  "postalCode": "96162",
  "state": "California",
  "triggerWelcomeEmail": false,
  "listIds": [
    "NdrDSPTeIvRMEtzufwDyKMWjmcOMsOxkxTCs"
  ],
  "identifiers": [
    {
      "type": "email",
      "id": "johndoe@gmail.com",
      "channels": {
        "email": {
          "status": "subscribed"
        }
      },
      "consent": {
        "createdAt": "2024-03-21T10:30:00.000Z",
        "ip": "192.168.1.1",
        "source": "web_form"
      }
    },
    {
      "type": "phone",
      "id": "+19013421324",
      "channels": {
        "phone": {
          "status": "subscribed"
        }
      },
      "consent": {
        "createdAt": "2024-03-21T10:30:00.000Z",
        "ip": "192.168.1.1",
        "source": "web_form"
      }
    }
  ]
}
```

### Example Responses

#### Successful Creation or Update (200 OK)

```json
{
  "status": true,
}
```

#### Error Responses

* **400 Bad Request**\
  Returned if any required fields are missing or invalid.

  ```json
  {
    "status": "error",
    "message": "Invalid request. 'identifiers' field is required."
  }
  ```
* **401 Unauthorized**\
  Returned if the provided API key or App ID is missing or invalid.

  ```json
  {
    "status": "error",
    "message": "Unauthorized access. Invalid or missing credentials."
  }
  ```
* **500 Internal Server Error**\
  Returned if an unexpected error occurred on the server.

  ```json
  {
    "status": "error",
    "message": "An unexpected error occurred."
  }
  ```

### Best Practices & Notes

1. **Identifiers Are Mandatory**\
   Always supply at least one item in the `identifiers` array so Retainful can correctly locate or create the contact.
2. **ISO 8601 Date Formats**\
   Ensure date fields (`birthDate`, `createdAt`, `consent.createdAt`) are valid ISO 8601 strings.
3. **Consent Accuracy**\
   Provide accurate IP and timestamp in the `consent` object to comply with privacy regulations.
4. **Subscription Management**\
   Use the `channels` field to manage a contact’s subscription status for different communication channels.
5. **Welcome Email**\
   Set `triggerWelcomeEmail` to `true` if you have configured an automated welcome email flow and want it triggered for this contact.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://help.retainful.com/developers/contacts.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
