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

# Contact and Company Tags

> How to create tags, apply them to contacts and companies in bulk, and filter searches by tag

## Overview

Tags are workspace labels that you apply directly to contacts and to companies, for example "Evento 1" on the contacts who attended an event. A contact or company can carry several tags, independently of the lists it belongs to.

Contact tags and company tags are two separate pools. A contact tag ID never works on a company endpoint, and the reverse is also true.

> [!NOTE]
>
> Tags are enabled per workspace. When they are not enabled, every tag endpoint and every search that filters
> by tag answers `400` with `details.code` set to `ENTITY_TAGS_NOT_ENABLED`. Retrying does not help: ask your
> Enginy account contact to enable them.

## Endpoints

| Contacts | Companies | What it does |
| - | - | - |
| `GET /v1/contacts/tags` | `GET /v1/companies/tags` | Lists the pool's tags, ordered by name |
| `POST /v1/contacts/tags` | `POST /v1/companies/tags` | Creates a tag, or returns the one with that name |
| `PATCH /v1/contacts/tag/{tagId}` | `PATCH /v1/companies/tag/{tagId}` | Renames or recolours a tag everywhere it is applied |
| `DELETE /v1/contacts/tag/{tagId}` | `DELETE /v1/companies/tag/{tagId}` | Deletes a tag and removes it from every record |
| `POST /v1/contacts/tags/add` | `POST /v1/companies/tags/add` | Applies tags to records in bulk |
| `POST /v1/contacts/tags/remove` | `POST /v1/companies/tags/remove` | Removes tags from records in bulk |

Reads need `CONTACTS_READ` or `COMPANIES_READ`. Writes need `CONTACTS_WRITE` or `COMPANIES_WRITE`, and are refused when the API key's creator is restricted from editing.

## Create a Tag

A tag has a name of 1 to 20 characters and a `#rrggbb` colour. The Enginy app offers `#767676` (gray), `#E99342` (orange), `#E367BC` (pink), `#6F78F0` (purple), `#F24473` (red), `#5BBE7E` (green), `#57A4E9` (blue) and `#5EB2CC` (cyan).

```bash theme={null}
curl -X POST "https://openapi.enginy.ai/v1/contacts/tags" \
  -H "x-api-key: $ENGINY_API_KEY" \
  -H "content-type: application/json" \
  -d '{ "name": "Evento 1", "color": "#57A4E9" }'
```

Names are unique within a pool, ignoring case. A new tag answers `201` with `created: true`. If "Evento 1" already exists, the call answers `200` with that tag and `created: false`, so you can call it safely before every import. Renaming a tag onto another tag's name answers `409`.

## Apply and Remove Tags

`POST /v1/contacts/tags/add` applies every tag in `tagIds` to every contact in `contactIds`. The company endpoint takes `companyIds` instead.

```bash theme={null}
curl -X POST "https://openapi.enginy.ai/v1/contacts/tags/add" \
  -H "x-api-key: $ENGINY_API_KEY" \
  -H "content-type: application/json" \
  -d '{ "contactIds": [101, 205], "tagIds": [12] }'
```

* One call takes up to 10,000 records and 50 tags. Split larger selections into several calls.
* Adding is idempotent: pairs that already exist are skipped, and `assigned` counts only the new ones.
* Removing deletes exactly the named record and tag pairs. The records' other tags stay.
* A record or tag ID outside your workspace rejects the whole call with `404` before anything is written.

## Read Tags on Records

Every contact and company response carries a `tags` array of `{ id, name, color }`, oldest assignment first. This covers the list, search and single-record endpoints and the update response. The array is empty when the workspace does not have tags enabled.

## Filter Searches by Tag

`POST /v1/contacts/search` accepts `contactTags`, the contact's own tags. `POST /v1/companies/search` accepts `companyTags`. Contact search does not filter by the tags of a contact's company and rejects `companyTags` as an unknown key. Values are tag IDs, as numbers or strings, and `""` means "no tag".

```json theme={null}
{
  "include": { "contactTags": [12, 13] },
  "exclude": { "contactTags": [14] }
}
```

* In `include`, a record matches when it carries any of the tags. Add `""` to also match records without tags.
* In `exclude`, a record is dropped when it carries any of the tags. Add `""` to also drop records without tags.

See [Searching contacts and companies](/api-reference/searching-contacts-companies) for the rest of the filter syntax.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.