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

# CompanyPhone

> CompanyPhone is a soft-deletable pivot (bridge) entity that links a Company to a Phone record, carrying contact-channel metadata (`is_primary`, `is_verify`, `la

CompanyPhone is a soft-deletable pivot (bridge) entity that links a Company to a Phone record, carrying contact-channel metadata (`is_primary`, `is_verify`, `label`). It enables a company to hold multiple phone numbers while designating exactly one primary via a partial unique index. The entity is written exclusively by the connector sync pipeline and enrichment flows; there is no user-facing PATCH route, and `company_phones` does not appear in `EDITABLE_FIELDS`.

| Naming                          | Value                             |
| ------------------------------- | --------------------------------- |
| Object                          | CompanyPhone                      |
| Resource type (JSON:API `type`) | `company_phone`                   |
| Collection / records root       | — <sub>(not a records root)</sub> |
| REST base                       | `/v1/company-phones`              |
| Entity class                    | `CompanyPhone`                    |

<Note>
  **Internal object.** Not currently exposed on the public REST API. The operations below describe the intended contract.
</Note>

## API operations

| Operation | Method & path                    | Status     |
| --------- | -------------------------------- | ---------- |
| List      | `GET /v1/company-phones`         | 🟡 Planned |
| Retrieve  | `GET /v1/company-phones/{id}`    | 🟡 Planned |
| Create    | `POST /v1/company-phones`        | 🟡 Planned |
| Update    | `PATCH /v1/company-phones/{id}`  | 🟡 Planned |
| Delete    | `DELETE /v1/company-phones/{id}` | 🟡 Planned |

## Data model

### Attributes

| Field       | Type                           | Required | Constraints                                                                                                                                       | Allowed values                                          | Description                                                                                                                    |
| ----------- | ------------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| is\_primary | boolean                        | ✅ Yes    | Partial unique index `uniq_company_phones_primary_company`: only one row per `company_pk` may have `is_primary = TRUE` where `deleted_at IS NULL` | true \| false                                           | Marks this phone as the canonical primary phone for the parent company. Enforced as unique per company among non-deleted rows. |
| is\_verify  | boolean                        | ✅ Yes    | None beyond NOT NULL                                                                                                                              | true \| false                                           | Indicates whether this phone number has been verified (e.g., via an automated or manual verification step).                    |
| label       | string                         | ✅ Yes    | varchar(255), NOT NULL                                                                                                                            | Free text (e.g. 'main', 'mobile', 'support', 'billing') | Human-readable tag for this phone association (e.g. 'main', 'billing'). Set by the ingestion pipeline from connector metadata. |
| created\_at | 🔒 system — Date (timestamptz) | ✅ Yes    | NOT NULL; set via `onCreate` hook                                                                                                                 | —                                                       | Timestamp of record creation. Set automatically on insert; never updated.                                                      |
| deleted\_at | Date \| null (timestamptz)     | ⚪ No     | Nullable; soft-delete sentinel. Partial unique index and forward composite index both include this column.                                        | —                                                       | Soft-delete timestamp. NULL means the record is active. Set by the pipeline on logical removal; never hard-deleted.            |

### Relationships

| Name    | Type               | Required | Description                                                                                                                                                                                                                                  |
| ------- | ------------------ | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| company | to-one (ManyToOne) | ✅ Yes    | The Company this phone belongs to. FK `company_pk` references `core_api.companies.pk` (ON UPDATE CASCADE). Composite index `idx_company_phones_company_deleted` covers `(company_pk, deleted_at)` for forward array-relationship traversals. |
| phone   | to-one (ManyToOne) | ✅ Yes    | The Phone atomic record that carries the actual phone number string. FK `phone_pk` references `core_api.phones.pk` (ON UPDATE CASCADE). Index `idx_company_phones_phone` covers `(phone_pk)` for reverse traversals.                         |

### System-computed

* pk — auto-increment serial primary key (internal, never exposed via API)
* created\_at — set by MikroORM onCreate hook to `new Date()` on insert; no onUpdate hook (column does not change after creation)
* deleted\_at — null at creation; set to current timestamp by soft-delete logic in the pipeline or repository layer; never hard-deleted under normal operation
* No `updated_at` column on this entity (audit trail is creation + soft-delete only)
* No `*_id` UUID public identifier on CompanyPhone itself — the pivot is referenced via its parent Company and Phone IDs in the API; internal pk is used for joins only
* Partial unique index `uniq_company_phones_primary_company` is enforced by the database engine on `(company_pk) WHERE deleted_at IS NULL AND is_primary IS TRUE` — only one active primary phone per company is permitted at the DB level
* Composite index `idx_company_phones_company_deleted (company_pk, deleted_at)` and reverse index `idx_company_phones_phone (phone_pk)` are maintained automatically; added by Migration20260416100000 to cover the forward and reverse array-relationship traversal patterns identified via production Query Insights

## Example

```json theme={null}
{
  "data": {
    "type": "company_phone",
    "id": "a3f7c821-91be-4d02-b56a-3e1234567890",
    "attributes": {
      "is_primary": true,
      "is_verify": false,
      "label": "main",
      "created_at": "2025-10-14T08:23:11.000Z",
      "deleted_at": null
    },
    "relationships": {
      "company": {
        "data": { "type": "company", "id": "9e2b1c44-0001-4321-abcd-000000000001" }
      },
      "phone": {
        "data": { "type": "phone", "id": "bb44f109-dead-beef-cafe-123456789abc" }
      }
    }
  }
}
```

<sub>Source: `apps/api/src/database/entities/CompanyPhone.ts` · domain: financial-graph · tier: Supporting</sub>
