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

# Contacts and consent

> Keeping OMNI's contacts in step with your own system: finding people by any number they've had, their fields and tags, and recording consent.

A contact is one person, with one main phone number and any others they've had, their
custom fields, tags, time zone and quiet hours, and their consent. The same contact is
behind every channel: their WhatsApp messages, SMS, calls and Inbox thread are all theirs.

## Finding someone

`GET /v1/contacts?phone=+919876543210` finds the contact who has that number **now, or
had it** — a number someone moved away from stays theirs, so their history follows them.
`q` searches names and numbers; `tag` filters by a tag.

## Adding and changing

```bash theme={null}
curl https://api.fireflo.au/v1/contacts \
  -H "Authorization: Bearer $OMNI_API_KEY" \
  -H "Idempotency-Key: crm-4417" \
  -H "Content-Type: application/json" \
  -d '{
    "phone": "98765 43210",
    "name": "Ravi Menon",
    "fields": {"city": "Kochi", "visits": 3},
    "tags": ["vip"],
    "timezone": "Asia/Kolkata",
    "quiet_hours": {"start": "21:00", "end": "08:00"}
  }'
```

* A number without a country code is read in your account's country.
* One number, one contact: adding a number someone already has is refused with
  `contact_exists`, naming them — update them instead.
* `fields` are checked against the custom fields your account has set up (a number field
  takes numbers, a date field dates). A key with no field set up is kept as text.
* Tags you name that don't exist yet are made.

`PATCH /v1/contacts/{contact_id}` changes only what you send. In `fields`, a `null`
clears that field and the rest stay. `tags` replaces their tags. A new `phone` keeps the
old one as theirs.

## Consent

`POST /v1/contacts/{contact_id}/consent` records that someone must **never be contacted**
— for good, or `until` a time — or lifts it:

```json theme={null}
{ "do_not_contact": true, "reason": "Asked on the phone", "until": "2027-01-01T00:00:00+05:30" }
```

While it stands, nothing is sent to them on any channel: messages fail with
`not_permitted`, and calls aren't placed. It is recorded as given through the API, with
your reason, and shown on their contact page.

Separately, people opt out themselves — replying STOP, or a channel's own opt-out — and
OMNI honours it on that channel or everywhere, as they asked. `consent.opted_out_at` in a
contact shows when.

Their **quiet hours** hold messages until the hours end; their **time zone** decides when
that is.


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