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

# Create a contact

> Create a new contact in your workspace.

Create a contact. Phone numbers are unique per workspace; emails are also unique per workspace when provided.

## Endpoint

```
POST /api/v1/{subdomain}/contacts
```

Required ability: `contacts.create`.

## Headers

| Header          | Value                        |
| --------------- | ---------------------------- |
| `Authorization` | `Bearer <your-64-hex-token>` |
| `Content-Type`  | `application/json`           |
| `Accept`        | `application/json`           |

## Path parameters

<ParamField path="subdomain" type="string" required={true}>
  Your workspace subdomain.
</ParamField>

## Body parameters

<ParamField body="firstname" type="string" required={true}>
  First name. Max 255 characters. **Note the spelling — `firstname`, not `first_name`.**
</ParamField>

<ParamField body="lastname" type="string" required={false}>
  Last name. Max 255 characters. Optional on create (required on update).
</ParamField>

<ParamField body="phone" type="string" required={true}>
  Phone number. Max 20 characters. Unique per workspace.
</ParamField>

<ParamField body="email" type="string" required={false}>
  Email address. Max 191 characters. When provided, must be unique per workspace.
</ParamField>

<ParamField body="type" type="string" required={true}>
  Contact type. Must be `lead` or `customer`. (The underlying enum also permits `guest`, but the API does not accept it.)
</ParamField>

<ParamField body="source_id" type="integer" required={true}>
  Id of an existing [Source](/developers/data-types#source) in your workspace.
</ParamField>

<ParamField body="status_id" type="integer" required={true}>
  Id of an existing [Status](/developers/data-types#status) in your workspace.
</ParamField>

<ParamField body="company" type="string" required={false}>
  Company name. Max 255 characters.
</ParamField>

<ParamField body="description" type="string" required={false}>
  Freeform description.
</ParamField>

<ParamField body="country_id" type="integer" required={false}>
  Country id.
</ParamField>

<ParamField body="assigned_id" type="integer" required={false}>
  User id of the owner.
</ParamField>

<ParamField body="groups" type="string" required={false}>
  Comma-separated group **names**. Groups that do not exist are auto-created.
</ParamField>

## Example request

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://dash.xobito.com/api/v1/acme/contacts \
    -H "Authorization: Bearer <your_token>" \
    -H "Content-Type: application/json" \
    -H "Accept: application/json" \
    -d '{
      "firstname": "John",
      "lastname": "Doe",
      "phone": "+14155551234",
      "email": "john@example.com",
      "type": "lead",
      "source_id": 2,
      "status_id": 1,
      "groups": "VIP,Newsletter"
    }'
  ```

  ```javascript JavaScript theme={null}
  const res = await fetch("https://dash.xobito.com/api/v1/acme/contacts", {
    method: "POST",
    headers: {
      Authorization: "Bearer <your_token>",
      "Content-Type": "application/json",
      Accept: "application/json",
    },
    body: JSON.stringify({
      firstname: "John",
      lastname: "Doe",
      phone: "+14155551234",
      email: "john@example.com",
      type: "lead",
      source_id: 2,
      status_id: 1,
      groups: "VIP,Newsletter",
    }),
  });
  const body = await res.json();
  ```

  ```python Python theme={null}
  import requests

  r = requests.post(
      "https://dash.xobito.com/api/v1/acme/contacts",
      headers={
          "Authorization": "Bearer <your_token>",
          "Accept": "application/json",
      },
      json={
          "firstname": "John",
          "lastname": "Doe",
          "phone": "+14155551234",
          "email": "john@example.com",
          "type": "lead",
          "source_id": 2,
          "status_id": 1,
          "groups": "VIP,Newsletter",
      },
  )
  body = r.json()
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init('https://dash.xobito.com/api/v1/acme/contacts');
  curl_setopt_array($ch, [
      CURLOPT_POST => true,
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => [
          'Authorization: Bearer <your_token>',
          'Content-Type: application/json',
          'Accept: application/json',
      ],
      CURLOPT_POSTFIELDS => json_encode([
          'firstname' => 'John',
          'lastname'  => 'Doe',
          'phone'     => '+14155551234',
          'email'     => 'john@example.com',
          'type'      => 'lead',
          'source_id' => 2,
          'status_id' => 1,
          'groups'    => 'VIP,Newsletter',
      ]),
  ]);
  $body = json_decode(curl_exec($ch), true);
  curl_close($ch);
  ```
</CodeGroup>

## Example response

```json 201 Created theme={null}
{
  "status": "success",
  "message": "Contact created successfully",
  "data": {
    "id": 451,
    "tenant_id": 13,
    "firstname": "John",
    "lastname": "Doe",
    "phone": "+14155551234",
    "email": "john@example.com",
    "type": "lead",
    "source_id": 2,
    "status_id": 1,
    "group_id": [7, 8],
    "is_enabled": 1,
    "is_opted_out": 0,
    "created_at": "2026-04-16T12:00:00.000000Z",
    "updated_at": "2026-04-16T12:00:00.000000Z"
  }
}
```

See [Data Types → Contact](/developers/data-types#contact) for every field.

## Error responses

| Status | When                    | Example body                                                                                                 |
| ------ | ----------------------- | ------------------------------------------------------------------------------------------------------------ |
| `401`  | Missing / invalid token | `{"status":"error","message":"API token is required"}`                                                       |
| `403`  | Missing ability         | `{"status":"error","message":"Token does not have the required ability: contacts.create"}`                   |
| `403`  | Plan limit hit          | `{"status":"error","message":"Contact limit exceeded for your current plan. Upgrade to add more contacts."}` |
| `422`  | Validation              | `{"status":"error","message":"Validation failed","errors":{"phone":["The phone has already been taken."]}}`  |
| `429`  | Rate limit              | `{"message":"Too many requests","retry_after":45}`                                                           |
| `500`  | Server error            | `{"status":"error","message":"Failed to create contact"}`                                                    |
