# Contacts

Source: https://kirora.io/docs/api/reference/contacts

A contact is one person you can message, with their profile, custom attributes, consent on each channel and topic choices. `identify` creates or updates a contact by your `externalId`, then email, then phone, so use it for every sync rather than looking contacts up by id first. Being on a list or in a segment is not consent: marketing reaches a contact only with consent on its channel. A contact's own records sit under it too: its lists, segments, topic choices, events, journeys, messages and push installations, each a device or browser registered by your own stable `externalInstallationId`. See [IDs and identity](https://kirora.io/docs/api/identifiers).

## Endpoints

- [List contacts](https://kirora.io/docs/api/reference/listContacts): `GET /v1/contacts`
- [Create or update a contact](https://kirora.io/docs/api/reference/identifyContact): `POST /v1/contacts/identify`
- [Identify contacts in a batch](https://kirora.io/docs/api/reference/identifyContactsBatch): `POST /v1/contacts/batch`
- [Retrieve a contact](https://kirora.io/docs/api/reference/getContact): `GET /v1/contacts/{id}`
- [Update a contact](https://kirora.io/docs/api/reference/updateContact): `PATCH /v1/contacts/{id}`
- [Delete a contact](https://kirora.io/docs/api/reference/deleteContact): `DELETE /v1/contacts/{id}`
- [Delete contacts](https://kirora.io/docs/api/reference/deleteContacts): `POST /v1/contacts/delete`
- [Merge a contact into another](https://kirora.io/docs/api/reference/mergeContacts): `POST /v1/contacts/{id}/merge`
- [List a contact's consent changes](https://kirora.io/docs/api/reference/listContactConsentChanges): `GET /v1/contacts/{id}/consent-changes`
- [Export a contact's data](https://kirora.io/docs/api/reference/getContactExport): `GET /v1/contacts/{id}/export`
- [List a contact's lists](https://kirora.io/docs/api/reference/listContactLists): `GET /v1/contacts/{id}/lists`
- [List a contact's segments](https://kirora.io/docs/api/reference/listContactSegments): `GET /v1/contacts/{id}/segments`
- [List a contact's topics](https://kirora.io/docs/api/reference/listContactTopics): `GET /v1/contacts/{id}/topics`
- [Set a contact's topic choice](https://kirora.io/docs/api/reference/setContactTopic): `PUT /v1/contacts/{id}/topics/{topicId}`
- [List a contact's events](https://kirora.io/docs/api/reference/listContactEvents): `GET /v1/contacts/{id}/events`
- [List a contact's journey enrollments](https://kirora.io/docs/api/reference/listContactJourneys): `GET /v1/contacts/{id}/journeys`
- [List a contact's messages](https://kirora.io/docs/api/reference/listContactMessages): `GET /v1/contacts/{id}/messages`
- [List a contact's push installations](https://kirora.io/docs/api/reference/listPushInstallations): `GET /v1/contacts/{id}/installations`
- [Register a push installation](https://kirora.io/docs/api/reference/registerPushInstallation): `POST /v1/contacts/{id}/installations`
- [Delete a push installation](https://kirora.io/docs/api/reference/deletePushInstallation): `DELETE /v1/contacts/{id}/installations/{externalInstallationId}`

## The ContactDetail object

```json
{
  "id": "0192f3a1-7c2e-7d4b-9a10-3e5f6a7b8c9d",
  "externalId": "customer-4821",
  "email": "amaka@example.com",
  "firstName": "Amaka",
  "lastName": "Obi",
  "phone": "+447700900123",
  "timezone": "Europe/London",
  "country": "GB",
  "locale": "en-NG",
  "rfm": {
    "group": "loyal",
    "recency": 3,
    "frequency": 4,
    "monetary": 5,
    "purchaseCount": 6,
    "totalSpent": {
      "currency": "USD",
      "value": 412.5
    },
    "lastPurchasedAt": "2026-03-02T18:20:00.000Z"
  },
  "dates": {
    "birthday": "1992-03-14"
  },
  "attributes": {
    "plan": "pro",
    "favourite_spice": "smoked paprika",
    "orders": 3
  },
  "consent": {
    "email": true,
    "push": false
  },
  "createdAt": "2026-09-12T08:15:00.000Z",
  "updatedAt": "2026-10-01T09:30:00.000Z",
  "emailSuppression": {
    "suppressed": false,
    "reason": null
  },
  "listIds": [
    "0192f3a2-1b3c-7e5d-8a21-4f6a7b8c9d0e"
  ]
}
```

- `id` (string, required, uuid)
- `externalId` (string | null, required) — Your own id for the contact, if set.
- `email` (string | null, required, email)
- `firstName` (string | null, required)
- `lastName` (string | null, required)
- `phone` (string | null, required) — Phone number in E.164 format.
- `timezone` (string | null, required) — IANA timezone, e.g. `Europe/London`.
- `country` (string | null, required) — ISO 3166-1 alpha-2 code: as written, or inferred from the phone, else the timezone.
- `locale` (string | null, required) — BCP 47 tag (`fr`, `fr-CA`): the language the contact reads (its first subtag), and how merge tags format numbers, dates and money for them.
- `rfm` (object | null, required) — The contact's RFM (recency, frequency and monetary value) group among the workspace's customers, from its purchase events (the workspace's `purchaseEvent`: an order, a paid invoice, a booking, a donation), each score from 1 to 5 (a fifth of the customers each; 5 is the most recent, most frequent or highest spend), and their purchase totals. Spend counts only purchases in the workspace's main currency; when the purchase carries no amount, `monetary` follows frequency. Recomputed daily, so a purchase today shows tomorrow; `null` for someone who has never purchased.
  - `group` (string, required, one of `champions`, `loyal`, `cant_lose_them`, `potential_loyalists`, `new_customers`, `need_attention`, `about_to_sleep`, `at_risk`, `hibernating`, `lost`)
  - `recency` (integer, required, min 1, max 5)
  - `frequency` (integer, required, min 1, max 5)
  - `monetary` (integer, required, min 1, max 5)
  - `purchaseCount` (integer, required, min > 0) — Their purchase events (the workspace's `purchaseEvent`), in any currency.
  - `totalSpent` (object | null, required) — What their purchases' amounts (`purchaseValueProperty`) add up to, in the workspace's main currency (`currency` on `GET /v1/reports/rfm`); purchases in other currencies and refunds are left out. `null` when the purchase carries no amount.
    - `currency` (string | null, required) — The currency, an ISO 4217 code; null when none was named.
    - `value` (number, required) — The amount in that currency.
  - `lastPurchasedAt` (string, required, date-time) — When their latest purchase happened.
- `dates` (map<string, string>, required) — Named calendar dates, e.g. `birthday`, as `YYYY-MM-DD` or `--MM-DD`.
- `attributes` (map<string, object>, required) — Custom attributes, keyed by attribute name.
- `consent` (ContactConsent, required) — Consent on each channel.
  - `email` (boolean, required) — Whether the contact has consented to email.
  - `push` (boolean, required) — Whether the contact has consented to push.
- `createdAt` (string, required, date-time)
- `updatedAt` (string, required, date-time)
- `emailSuppression` (object, required)
  - `suppressed` (boolean, required) — Whether email to this contact is blocked.
  - `reason` (string | null, required) — Why email to this contact is suppressed: `bounced`, `complained`, `complained_transactional`, `unsubscribed`, `manual`, `imported`, or `other_workspace` (a bounce or complaint in another workspace with the same owner or partner).
- `listIds` (string[], required) — Ids of the lists the contact is in.
