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

# Find or Create Contact

> POST /partners/contacts — Register a customer and optionally create a service address.

## Overview

Registers a customer contact and optionally creates a service address. Returns `id` (use as `contactId`) and `addressId` for booking and timeslot requests.

Call this endpoint **before** `POST /partners/bookings`.

***

## Endpoint

```
POST /partners/contacts
```

## Authentication

Requires a valid API Key with the `partner_contacts_read` permission.

## Request Headers

| Header         | Required | Value                |
| -------------- | -------- | -------------------- |
| `x-api-key`    | Yes      | Your partner API key |
| `Content-Type` | Yes      | `application/json`   |

***

## Request Body

**Minimal (contact only):**

```json theme={null}
{
  "phone": "+966500000000",
  "name": "Ahmed Ali"
}
```

**With address (recommended before booking):**

```json theme={null}
{
  "phone": "+966500000000",
  "name": "Ahmed Ali",
  "latitude": "24.7136",
  "longitude": "46.6753",
  "cityName": "Riyadh",
  "districtName": "Al Olaya",
  "streetName": "King Fahd Road"
}
```

### Field Reference

| Field          | Type   | Required | Description                                                                   |
| -------------- | ------ | -------- | ----------------------------------------------------------------------------- |
| `phone`        | string | **Yes**  | Saudi phone number in international format (e.g. `+966500000000`). No spaces. |
| `name`         | string | **Yes**  | Customer full name.                                                           |
| `latitude`     | string | No       | Address latitude (e.g. `"24.7136"`). Must be sent together with `longitude`.  |
| `longitude`    | string | No       | Address longitude (e.g. `"46.6753"`). Must be sent together with `latitude`.  |
| `cityName`     | string | No       | City name for the service address.                                            |
| `districtName` | string | No       | District / neighborhood name for the service address.                         |
| `streetName`   | string | No       | Street name for the service address.                                          |

<Note>
  `utmSource` is assigned automatically from your partner account name — do not send it in the request body.
</Note>

***

## Example Request

```bash theme={null}
curl -X POST "https://apiv3.thecleanlife.dev/v1/partners/contacts" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "+966500000000",
    "name": "Ahmed Ali",
    "latitude": "24.7136",
    "longitude": "46.6753",
    "cityName": "Riyadh",
    "districtName": "Al Olaya",
    "streetName": "King Fahd Road"
  }'
```

***

## Success Response

**HTTP Status:** `200 OK`

**Contact without address:**

```json theme={null}
{
  "success": true,
  "data": {
    "id": "aaaaaaaa-0000-0000-0000-000000000001",
    "name": "Ahmed Ali",
    "phone": "+966500000000",
    "addressId": null,
    "isNewContact": true
  }
}
```

**Contact with address created:**

```json theme={null}
{
  "success": true,
  "data": {
    "id": "bbbbbbbb-0000-0000-0000-000000000002",
    "name": "Ahmed Ali",
    "phone": "+966500000000",
    "addressId": "cccccccc-0000-0000-0000-000000000003",
    "isNewContact": true
  }
}
```

### Response Fields

| Field          | Type         | Description                                                                                      |
| -------------- | ------------ | ------------------------------------------------------------------------------------------------ |
| `id`           | UUID         | Contact ID — pass as `contactId` in `POST /partners/bookings`                                    |
| `name`         | string       | Contact name                                                                                     |
| `phone`        | string       | Normalized phone number                                                                          |
| `addressId`    | UUID \| null | Service address ID when an address was created or matched; `null` if no address fields were sent |
| `isNewContact` | boolean      | `true` when a new contact record was created                                                     |

***

## Error Responses

| HTTP Status | Code               | Description                                                           |
| ----------- | ------------------ | --------------------------------------------------------------------- |
| `400`       | `VALIDATION_ERROR` | Invalid phone format, invalid coordinates, or missing required fields |
| `401`       | `UNAUTHORIZED`     | Invalid or missing API key                                            |
| `403`       | `FORBIDDEN`        | Missing `partner_contacts_read` permission                            |

***

## Notes

* Store the returned `id` as `contactId` and `addressId` in your booking request.
* When you send `latitude` and `longitude` together with address text fields, use the returned `addressId` directly in `POST /partners/bookings` and `GET /partners/timeslots/available`.
* `latitude` and `longitude` must both be provided to set coordinates; sending only one is ignored for location matching.
* Phone numbers are normalized server-side — always use the international `+966` format.

***

## Related Endpoints

* `POST /partners/bookings` — Create a booking using the returned `id` as `contactId` and `addressId`
* `GET /partners/services?addressId=...` — List services available at the returned address
* `GET /partners/timeslots/available` — Check timeslots using `addressId`
