# 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.
