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

# Attach Contact Company

> Attach a contact to a company, moving it off any company it currently belongs to

## Overview

This endpoint attaches a contact to a company. A contact belongs to at most **one company per Space**, so attaching it to a new company moves it off any company it currently belongs to.

In the same transaction, the contact's conversions, touchpoints, and visit metadata are re-stamped with the new company id, so company-level reports and the [Companies dataset](/data-warehouse/datasets/companies) `company_id` columns in the data warehouse follow immediately — nothing is left pointing at the old company.

This call is **idempotent**: repeating it with the contact's current company id re-stamps the same rows again, which is useful for repairing rows that drifted out of sync rather than a no-op.

## Path Parameters

<ParamField path="id" type="integer" required>
  The unique identifier of the contact to attach. Merged profile aliases are automatically resolved to the current canonical contact — the response's `id` is the surviving contact.
</ParamField>

## Request Body

<ParamField body="company_id" type="integer" required placeholder="12345">
  The unique identifier of the company to attach the contact to. Must belong to a company in the same Space as the contact.
</ParamField>

## Response

### Success Response

<ResponseField name="id" type="integer">
  The unique identifier of the contact (after resolving merged-profile aliases).
</ResponseField>

<ResponseField name="company_id" type="integer">
  The id of the company the contact is now attached to — echoes the `company_id` sent in the request.
</ResponseField>

### Error Response

<ResponseField name="message" type="string">
  Error description explaining what went wrong.
</ResponseField>

## Example Requests

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT "https://app.cometly.com/public-api/v1/contacts/12345/company" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Accept: application/json" \
    -H "Content-Type: application/json" \
    -d '{
      "company_id": 54321
    }'
  ```

  ```javascript JavaScript theme={null}
  const contactId = 12345;
  const response = await fetch(`https://app.cometly.com/public-api/v1/contacts/${contactId}/company`, {
    method: 'PUT',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      company_id: 54321
    })
  });

  const data = await response.json();
  console.log('Attached company:', data);
  ```

  ```php PHP theme={null}
  <?php
  $contactId = 12345;
  $url = 'https://app.cometly.com/public-api/v1/contacts/' . $contactId . '/company';
  $headers = [
      'Authorization: Bearer YOUR_API_KEY',
      'Accept: application/json',
      'Content-Type: application/json'
  ];

  $data = [
      'company_id' => 54321,
  ];

  $ch = curl_init();
  curl_setopt($ch, CURLOPT_URL, $url);
  curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
  curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
  curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
  curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);

  $response = curl_exec($ch);
  $result = json_decode($response, true);
  curl_close($ch);
  ?>
  ```

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

  contact_id = 12345
  url = f'https://app.cometly.com/public-api/v1/contacts/{contact_id}/company'
  headers = {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Accept': 'application/json',
      'Content-Type': 'application/json'
  }

  data = {
      'company_id': 54321,
  }

  response = requests.put(url, headers=headers, json=data)
  result = response.json()
  ```
</CodeGroup>

## Status Codes

| Status Code | Description                                                                               |
| ----------- | ----------------------------------------------------------------------------------------- |
| 200         | Contact successfully attached to the company                                              |
| 401         | Missing or invalid API key                                                                |
| 403         | API key doesn't have permission or subscription is inactive                               |
| 404         | Contact not found, or `company_id` does not match a company in this Space                 |
| 422         | Invalid parameters provided (check error message for details)                             |
| 429         | Too many requests - rate limit exceeded. See [Rate Limiting](/introduction/rate-limiting) |

## Notes

* **Rate Limit**: This endpoint has a limit of **60 requests per minute** per Space. See [Rate Limiting](/introduction/rate-limiting) for details, the same bucket as [Update Contact](/api-reference/endpoint/update-contact).
* **One company per contact**: attaching a contact to a new company removes it from any company it previously belonged to — a contact is never attached to more than one company at a time.
* **Rows are re-stamped, not just the pivot**: the contact's conversions, touchpoints, and visit metadata are updated to the new `company_id` in the same transaction, so company-level reports and the data warehouse [Companies dataset](/data-warehouse/datasets/companies) join correctly right away.
* **Idempotent repair**: calling this again with the contact's current company id is not a no-op — it re-stamps the contact's rows, which repairs any that had drifted out of sync.
* **Merged profiles**: If you pass an ID that was merged into another profile, the attach is applied to the canonical (current) profile, and the response's `id` is that canonical id.
* **`company_id` must be in the same Space**: attaching to a company from a different Space returns `404`.
* **Behavior after a manual attach depends on company identity mode**: in the default **Auto** mode, the tracker only assigns a company to a contact that currently has none, so a manual attach sticks until the contact is manually detached — it is not undone by a later event. In **External ID** mode, the next event carrying a different `company_external_id` re-points the contact again.
