# Update company attributes

> PUT /v1/companies/{id} · Core resources API

Source: https://developer.kustomer.com/api/core-resources/update-company-attributes

```http
PUT https://{orgname}.api.kustomerapp.com/v1/companies/{id}
Authorization: Bearer <API key>
```

## Authorization

Requires any one of these roles: `org.permission.company.update`; or legacy `org.user.company.write`. The API key or user must hold at least one of them. Legacy roles predate permission sets and still work.

Updates the attributes of a company based on the company ID.

### Note
>This endpoint is subject to Object Rate Limiting, which limits how many updates a single user can make to a single company attribute. To learn more, see [Rate limiting](https://developer.kustomer.com/docs/concepts/rate-limits).

>Setting `deleted: true` on a company that still has one or more children in a hierarchy tree (see [Companies (Hierarchy)](#tag/Companies-Hierarchy)) returns a `409 conflict` naming the first blocking child and the tree it appears in, and does not delete the company. The check spans every hierarchy tree the company participates in — not just `company_hierarchy`. Unlink or delete that child first — for example with `DELETE /kedge/{childId}/parent?name=<tree>`, using the tree name from the error message. If the company has blocking children in more than one tree, repeat until all are cleared.

### Custom Attributes
[Custom attributes](https://help.kustomer.com/define-attributes-Skr924HI) are optional and allow you to specify
custom key-value pairs.

Kustomer uses a naming convention for custom attributes to specify the field data type with a name suffix:

#### Naming Suffix

* `Num` *number* or *null*
* `At` *date-time* or *null*
* `Str` *string* or *null*, length: [ 0 .. 1024 ] characters
* `Txt` *string* or *null*, length: [ 0 .. 1024 ] characters
* `Bool` *boolean* or *null*
* `Url` *string* or *null*, format: *uri*

## About Companies

A company is an organization that your customers belong to, such as a business account. It holds the organization's contact details, tags and custom attributes, can own custom objects, and can sit in a parent-child hierarchy with other companies.

Companies group customers who belong to the same organization, which matters most for B2B support: agents can see which account a person works for, and searches, workflows and reports can filter on company data. A customer links to one company through its `company` attribute, which holds the company ID. Companies are usually created by a CRM sync or an import, then kept up to date as the source system changes. There is no `DELETE` endpoint: you delete a company by updating it with `deleted: true`.

#### Key fields

`name` is the only required field. Set `externalId` to the account's ID in your own system so you can find it again: `GET /v1/companies` accepts `externalId`, or `filter` for a name match, but if you send both, both are ignored. The contact lists `emails`, `phones`, `whatsapps`, `socials`, `urls`, `domains` and `locations` each hold up to 10 entries, and `tags` holds up to 20. Your own fields go in `custom`, named with a type suffix such as `tierStr` or `seatsNum`; see [custom attributes](https://developer.kustomer.com/docs/concepts/custom-attributes).

Updates merge into the existing company by default. Add `replace=true` to replace the whole resource. Updates are subject to object rate limiting, which caps how often one user can change the same company; see [rate limits](https://developer.kustomer.com/docs/concepts/rate-limits).

#### Hierarchies

The hierarchy endpoints link existing companies into trees, such as a parent company and its subsidiaries. Each link is an edge of type `kedge` with its own ID: `sourceId` is the parent and `targetId` is the child. Edges belong to a named tree (`name`, default `company_hierarchy`), and a company has at most one parent per tree, so setting a new parent replaces the old edge. A tree can be at most 20 levels deep and hold at most 2,000 companies. Cycles and self-parenting fail with `400`.

Most hierarchy endpoints take a company ID. The exception is `DELETE /v1/kedge/{id}`, which takes an edge ID. Reading a company returns a `kedge-node` with its parent edge, one page of direct children, and `breadcrumbs` from the root down to the company itself.

#### Which endpoint to use

| To | Call |
| --- | --- |
| List companies, or find one by `externalId` or name | [`GET /v1/companies`](https://developer.kustomer.com/api/core-resources/get-companies) |
| Create, read or update a company (including deleting it with `deleted: true`) | [`POST /v1/companies`](https://developer.kustomer.com/api/core-resources/create-company), [`GET`](https://developer.kustomer.com/api/core-resources/get-company-by-id) or [`PUT /v1/companies/{id}`](https://developer.kustomer.com/api/core-resources/update-company-attributes) |
| List a company's custom objects of one Klass | [`GET /v1/companies/{id}/klasses/{name}`](https://developer.kustomer.com/api/core-resources/find-company-kobjects-custom-objects) |
| Create or update up to 100 companies at once | [`POST`](https://developer.kustomer.com/api/core-resources/bulk-create-companies) or [`PUT /v1/companies/bulk`](https://developer.kustomer.com/api/core-resources/bulk-batch-update-companies) |
| Link a child to a parent | [`POST /v1/kedge`](https://developer.kustomer.com/api/core-resources/create-a-company-hierarchy-edge) or [`POST /v1/kedge/{id}/parent`](https://developer.kustomer.com/api/core-resources/set-a-companys-parent) |
| Read a company's place in the tree | [`GET /v1/kedge/{id}`](https://developer.kustomer.com/api/core-resources/get-a-company-hierarchy-node), or [`GET /v1/kedge/{id}/parent`](https://developer.kustomer.com/api/core-resources/get-a-companys-direct-parent-edge) for just the parent edge (`404` for a root) |
| Make a company a root, keeping its children | [`DELETE /v1/kedge/{id}/parent`](https://developer.kustomer.com/api/core-resources/remove-a-companys-parent) |
| Delete one edge by its edge ID | [`DELETE /v1/kedge/{id}`](https://developer.kustomer.com/api/core-resources/delete-a-company-hierarchy-edge) |

Bulk requests run asynchronously and return a bulk operation; poll it with the [bulk operations](https://developer.kustomer.com/api/core-resources#bulk-operations) endpoints. Add `_clientRef` to every item to match per-item results back to your rows. Deleting a company that still has children in any tree fails with `409 Conflict`, naming the first blocking child and its tree; unlink or delete that child first. A `409` on an edge write means another write to the same tree was in progress, so retry it.

Related: [Customers](https://developer.kustomer.com/api/core-resources#customers), [Model company hierarchies](https://developer.kustomer.com/docs/guides/company-hierarchy), [Bulk operations](https://developer.kustomer.com/docs/guides/bulk-operations), [KObjects (custom objects)](https://developer.kustomer.com/api/core-resources#kobjects-custom-objects)

### Recipes

#### 1. Find or create a company by your account ID

Map an account in your CRM to one Kustomer company, so a sync can run again without creating duplicates.

**Step 1.** [`GET /v1/companies`](https://developer.kustomer.com/api/core-resources/get-companies.md). Look the company up by the account's ID, which you store in `externalId`. The response is a list: the company is the first item in `data`, and an empty list means it doesn't exist yet. Don't add `filter` to the same request, because sending both parameters makes the API ignore both.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/companies?externalId=$ACCOUNT_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/companies --query externalId=$ACCOUNT_ID | jq -r '.data[0].id // empty'
```

**Step 2.** [`POST /v1/companies`](https://developer.kustomer.com/api/core-resources/create-company.md). If there's no match, create the company. `name` needs at least 3 characters. Lists such as `domains` (each `{ domain }`), `emails` and `phones` hold up to 10 entries, and custom attributes go under `custom` with a type suffix such as `tierStr`. Keep `data.id`; customers link to the company by that ID.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/companies" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"name\": \"$ACCOUNT_NAME\", \"externalId\": \"$ACCOUNT_ID\", \"domains\": [{\"domain\": \"acme.example\"}], \"custom\": {\"tierStr\": \"enterprise\"}}"
```

```bash title="kusty"
kusty api POST /v1/companies \
  --field name="$ACCOUNT_NAME" --field externalId=$ACCOUNT_ID \
  --field domains.0.domain=acme.example --field custom.tierStr=enterprise \
  | jq -r .data.id
```

**Step 3.** [`PUT /v1/companies/{id}`](https://developer.kustomer.com/api/core-resources/update-company-attributes.md). When the account changes later, update the company. Fields you leave out are kept unless you add `replace=true`. Skip the call when nothing changed: one company can only be updated so often in a short window (see [Rate limits](https://developer.kustomer.com/docs/concepts/rate-limits#object-limits)).

```bash title="cURL"
curl --request PUT "https://api.kustomerapp.com/v1/companies/$COMPANY_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"custom": {"tierStr": "strategic"}}'
```

```bash title="kusty"
kusty api PUT /v1/companies/$COMPANY_ID --field custom.tierStr=strategic
```

> For a first import of many accounts, use [`POST /v1/companies/bulk`](https://developer.kustomer.com/api/core-resources/bulk-create-companies) with `_clientRef` on each item, and poll the job as described in [Bulk operations](https://developer.kustomer.com/docs/guides/bulk-operations).

#### 2. Link a customer to their company

Attach a person to the account they work for, so agents see the company on the customer's profile and searches can filter by company.

**Step 1.** [`PUT /v1/customers/{id}`](https://developer.kustomer.com/api/core-resources/update-customer.md). Set the customer's `company` to the company ID. A customer belongs to at most one company. Remember that every later `PUT` on the customer must include `company` too, because leaving it out unlinks them.

```bash title="cURL"
curl --request PUT "https://api.kustomerapp.com/v1/customers/$CUSTOMER_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"company\": \"$COMPANY_ID\"}"
```

```bash title="kusty"
kusty api PUT /v1/customers/$CUSTOMER_ID --field company=$COMPANY_ID
```

**Step 2.** [`GET /v1/customers/{id}`](https://developer.kustomer.com/api/core-resources/get-customer-by-id.md). Read the customer with `include=company` to get the company record alongside it in one call, for example to show the account name and tier next to the person.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/customers/$CUSTOMER_ID?include=company" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/customers/$CUSTOMER_ID --query include=company
```

> To link many customers at once, send `{ "id", "company" }` items to [`PUT /v1/customers/bulk`](https://developer.kustomer.com/api/core-resources/bulk-batch-update-customers), up to 100 per request.

#### 3. Put a subsidiary under its parent company

Mirror a corporate structure, such as a parent account and its regional offices, in Kustomer's company hierarchy.

**Step 1.** [`POST /v1/kedge/{id}/parent`](https://developer.kustomer.com/api/core-resources/set-a-companys-parent.md). Call this on the child company with the parent's ID as `parentId`. A company has one parent per tree, so this replaces any parent it already had. Trees are named; leave out `name` to use the default `company_hierarchy`. Making a company its own parent or creating a cycle fails with `400`, and a `409` means another write to the same tree was in progress, so retry.

```bash title="cURL"
curl --request POST "https://api.kustomerapp.com/v1/kedge/$CHILD_ID/parent" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data "{\"parentId\": \"$PARENT_ID\"}"
```

```bash title="kusty"
kusty api POST /v1/kedge/$CHILD_ID/parent --field parentId=$PARENT_ID
```

**Step 2.** [`GET /v1/kedge/{id}`](https://developer.kustomer.com/api/core-resources/get-a-company-hierarchy-node.md). Read the child's place in the tree. `parent` is the edge to its parent, `children` is one page of its direct children, and `breadcrumbs` runs from the root down to the company itself, ready to show as a path such as "Acme Corp › Acme EMEA".

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/kedge/$CHILD_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/kedge/$CHILD_ID | jq -r '[.data.attributes.breadcrumbs[].displayName] | join(" › ")'
```

> A tree can be at most 20 levels deep and hold at most 2,000 companies. [Model company hierarchies](https://developer.kustomer.com/docs/guides/company-hierarchy) covers multiple trees and moving whole branches.

#### 4. Delete a company that has subsidiaries

Remove a company you no longer need, first detaching any child companies that would block the delete.

**Step 1.** [`GET /v1/kedge/{id}`](https://developer.kustomer.com/api/core-resources/get-a-company-hierarchy-node.md). List the company's direct children. Each item in `children` is an edge whose `targetId` is a child company ID. Pass `name` if the company is in a tree other than `company_hierarchy`.

```bash title="cURL"
curl "https://api.kustomerapp.com/v1/kedge/$COMPANY_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api GET /v1/kedge/$COMPANY_ID | jq -r '.data.attributes.children[].attributes.targetId'
```

**Step 2.** [`DELETE /v1/kedge/{id}/parent`](https://developer.kustomer.com/api/core-resources/remove-a-companys-parent.md). For each child, remove its parent edge. The child becomes a root and keeps its own children. This takes the child's company ID, not the edge ID.

```bash title="cURL"
curl --request DELETE "https://api.kustomerapp.com/v1/kedge/$CHILD_ID/parent" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY"
```

```bash title="kusty"
kusty api DELETE /v1/kedge/$CHILD_ID/parent --confirm --yes
```

**Step 3.** [`PUT /v1/companies/{id}`](https://developer.kustomer.com/api/core-resources/update-company-attributes.md). There's no `DELETE` for companies; you delete one by sending `deleted: true`. If a child is still attached in any tree, the API answers `409 Conflict` and names the first blocking child and its tree; detach it with `name` set to that tree and try again.

```bash title="cURL"
curl --request PUT "https://api.kustomerapp.com/v1/companies/$COMPANY_ID" \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header "Content-Type: application/json" \
  --data '{"deleted": true}'
```

```bash title="kusty"
kusty api PUT /v1/companies/$COMPANY_ID --field deleted:=true
```

### Example object

A real record from [`GET /v1/companies`](https://developer.kustomer.com/api/core-resources/get-companies.md):

```json
{
  "type": "company",
  "id": "58224b3eaa5f92110005d61e",
  "attributes": {
    "name": "foobar Company Name",
    "externalId": "foobar",
    "createdAt": "2016-11-08T22:01:34.620Z",
    "updatedAt": "2016-11-08T22:11:35.776Z",
    "modifiedAt": "2016-11-08T22:11:35.776Z",
    "tags": [
      "58224d97d4e96711004ecc56"
    ]
  },
  "relationships": {
    "org": {
      "links": {
        "self": "/v1/orgs/57f29863a1dbf61100e6aa92"
      },
      "data": {
        "type": "org",
        "id": "57f29863a1dbf61100e6aa92"
      }
    },
    "createdBy": {
      "links": {
        "self": "/v1/users/58190b991f2932100010d683"
      },
      "data": {
        "type": "user",
        "id": "58190b991f2932100010d683"
      }
    },
    "modifiedBy": {
      "links": {
        "self": "/v1/users/58190b991f2932100010d683"
      },
      "data": {
        "type": "user",
        "id": "58190b991f2932100010d683"
      }
    }
  },
  "links": {
    "self": "/v1/companies/58224b3eaa5f92110005d61e"
  }
}
```

Fields:

- `attributes.name` (string): The company's name, 3 to 256 characters. The only field required on create.
- `attributes.externalId` (string): The account's ID in your CRM or other system, up to 256 characters. Find the company again with `GET /v1/companies?externalId=…`.
- `attributes.createdAt` (string): When the company was created in Kustomer. You can set it on create when importing, along with `importedAt`.
- `attributes.modifiedAt` (string): When the company was last changed.
- `attributes.tags` (array): Tag IDs, up to 20. Sending `tags` on an update replaces the whole list.
- `relationships.createdBy` (object): The user or API key that created the company.

### Relationships

- Referenced by **Customers** via `relationships.company`: The company this customer belongs to. A customer has at most one; set it by sending the company ID as `company`, and resend it on every `PUT`, because leaving it out unlinks the customer.
- Referenced by **KObjects (custom objects)** via `relationships.company`: The company whose timeline shows this KObject, set with `company` when you create it. List them with `GET /v1/companies/{id}/klasses/{name}`.

### Permissions

Fewest roles for a read-only integration: `org.permission.company.read`. For every endpoint: `org.permission.company.update`, `org.permission.company.read`, `org.permission.company.create`.

### Events

Workflow triggers:

- `kustomer.company.create` (Company Created): A company is created
- `kustomer.company.update` (Company Updated): A company changes

Workflow actions:

- `kustomer.company.create` (Company: Create): required inputs `name`
- `kustomer.company.update` (Company: Update): required inputs `id`
- `kustomer.company.find` (Company: Lookup (By ID)): required inputs `identifier`
- `kustomer.company.find-by-external-id` (Company: Lookup (By External ID)): required inputs `externalId`

## Path parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `id` | string | yes | Company ID. |

## Query parameters

| Name | Type | Required | Description |
| --- | --- | --- | --- |
| `replace` | boolean | no | Set to `true` to replace the full resource instead of applying patch semantics. |

## Request body

Content type: `application/json` (required)

- `name` (string): (min length 3; max length 256)
- `externalId` (string, nullable): (max length 256)
- `avatarUrl` (string<uri>, nullable)
- `emails` (array<email>): (max items 10; unique items)
  - `type` (string): One of: `home`, `work`, `other`.
  - `email` (string<email-relaxed>, required)
  - `verified` (boolean)
- `phones` (array<phone>): (max items 10; unique items)
  - `type` (string): One of: `mobile`, `home`, `work`, `fax`, `other`.
  - `phone` (string<phone-number>, required)
  - `verified` (boolean)
- `whatsapps` (array<whatsapp>): (max items 10; unique items)
  - `type` (string): One of: `mobile`.
  - `phone` (string<whatsapp-number>, required)
  - `verified` (boolean)
- `socials` (array<social>): (max items 10; unique items)
  - `type` (string, required): One of: `twitter`, `facebook`, `instagram`, `linkedin`, `pinterest`.
  - `userid` (string): (max length 256)
  - `username` (string, required): (min length 1; max length 256)
  - `url` (string<uri>)
  - `verified` (boolean)
- `urls` (array<url>): (max items 10; unique items)
  - `type` (string): One of: `website`, `blog`, `other`.
  - `url` (string<url>, required)
- `domains` (array<domain>): (max items 10; unique items)
  - `domain` (string<domain-name>, required)
- `locations` (array<location>): (max items 10; unique items)
  - `type` (string, nullable): One of: `home`, `work`, `other`.
  - `name` (string, nullable)
  - `address` (string, nullable): (max length 256)
  - `address2` (string, nullable): (max length 256)
  - `address3` (string, nullable): (max length 256)
  - `latitude` (number, nullable)
  - `longitude` (number, nullable)
  - `countryCode` (string, nullable): (min length 2; max length 2)
  - `countryName` (string, nullable): (max length 64)
  - `regionCode` (string, nullable): (max length 2)
  - `regionName` (string, nullable): (max length 128)
  - `cityName` (string, nullable): (max length 128)
  - `zipCode` (string, nullable): (max length 30)
  - `areaCode` (string, nullable): (max length 30)
- `employeeCount` (number)
- `tags` (array<tag_name>): (max items 20; unique items)
- `custom` (object)
- `defaultLang` (string, nullable): (max length 100)
- `rev` (number)
- `deleted` (boolean, nullable)

Example:

```json
{
  "name": "example_name",
  "externalId": "crm-10293",
  "emails": [
    {
      "type": "home",
      "email": "jane.doe@example.com",
      "verified": true
    }
  ],
  "phones": [
    {
      "type": "mobile",
      "phone": "+15555550123",
      "verified": true
    }
  ],
  "tags": [
    "vip"
  ],
  "custom": {}
}
```

## Responses

### 200

OK

- `data` (object, required)
  - `type` (string, required)
  - `id` (string, required)
  - `attributes` (object, required)
    - `name` (string, required)
    - `createdAt` (string, required)
    - `updatedAt` (string, required)
    - `modifiedAt` (string, required)
    - `tags` (array<string>, required)
  - `relationships` (object, required)
    - `org` (object, required)
    - `createdBy` (object, required)
    - `modifiedBy` (object, required)
  - `links` (object, required)
    - `self` (string, required)

```json
{
  "data": {
    "type": "company",
    "id": "58224b3eaa5f92110005d61e",
    "attributes": {
      "name": "Updated Company Name",
      "createdAt": "2016-11-08T22:01:34.620Z",
      "updatedAt": "2016-11-08T22:11:35.776Z",
      "modifiedAt": "2016-11-08T22:11:35.776Z",
      "tags": [
        "58224d97d4e96711004ecc56"
      ]
    },
    "relationships": {
      "org": {
        "links": {
          "self": "/v1/orgs/57f29863a1dbf61100e6aa92"
        },
        "data": {
          "type": "org",
          "id": "57f29863a1dbf61100e6aa92"
        }
      },
      "createdBy": {
        "links": {
          "self": "/v1/users/58190b991f2932100010d683"
        },
        "data": {
          "type": "user",
          "id": "58190b991f2932100010d683"
        }
      },
      "modifiedBy": {
        "links": {
          "self": "/v1/users/58190b991f2932100010d683"
        },
        "data": {
          "type": "user",
          "id": "58190b991f2932100010d683"
        }
      }
    },
    "links": {
      "self": "/v1/companies/58224b3eaa5f92110005d61e"
    }
  }
}
```

### 400

Bad Request

### 401

Unauthorized

### 403

Forbidden

### 404

Not Found

### 409

Conflict

## Example request

```bash
curl --request PUT \
  --url 'https://api.kustomerapp.com/v1/companies/6195640664b2fbb9eddc1e9b' \
  --header "Authorization: Bearer $KUSTOMER_API_KEY" \
  --header 'Content-Type: application/json' \
  --data '{
  "name": "example_name",
  "externalId": "crm-10293",
  "emails": [
    {
      "type": "home",
      "email": "jane.doe@example.com",
      "verified": true
    }
  ],
  "phones": [
    {
      "type": "mobile",
      "phone": "+15555550123",
      "verified": true
    }
  ],
  "tags": [
    "vip"
  ],
  "custom": {}
}'
```
