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

# Sync contacts from your system

> Keep Qall's contacts in step with your own database.

If callers already exist in your CRM, push them to Qall so an inbound call
arrives with a name attached and your assistant can greet them properly.

## Use your own id

Set `external_id` to your system's id for that person. It's unique per
organisation, so you can look a contact up by it later without storing Qall's id
on your side.

<CodeGroup>
  ```bash cURL theme={null}
  curl https://qall.io/api/contacts \
    -H "Authorization: Bearer $QALL_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "external_id": "crm-88312",
      "first_name": "Jana",
      "last_name": "Albrecht",
      "phone_number": "+4930111111",
      "email": "jana.albrecht@example.com",
      "timezone": "Europe/Berlin"
    }'
  ```

  ```python Python theme={null}
  import os, requests

  requests.post(
      "https://qall.io/api/contacts",
      headers={"Authorization": f"Bearer {os.environ['QALL_API_KEY']}"},
      json={
          "external_id": "crm-88312",
          "first_name": "Jana",
          "last_name": "Albrecht",
          "phone_number": "+4930111111",
          "email": "jana.albrecht@example.com",
          "timezone": "Europe/Berlin",
      },
      timeout=30,
  ).raise_for_status()
  ```
</CodeGroup>

Phone numbers and emails are normalised before they're stored, so you don't have
to format them perfectly — but E.164 (`+4930111111`) is safest.

## Sending your own fields

Create the properties once under [Contacts](/contacts), then set them per
contact. Values are coerced to the property's type, so a date property won't
accept "next Tuesday".

```json theme={null}
{
  "external_id": "crm-88312",
  "custom_fields": { "tier": "gold", "renewal_date": "2027-03-14" }
}
```

Those are then available to the assistant as `{{contact.tier}}`. See
[Variables](/variables).

## Duplicates

Phone number, email and `external_id` are each unique within your organisation.
Posting a contact whose number already exists returns a conflict rather than
creating a second record — which is what you want, since the whole point is one
record per person.

If you're syncing in bulk, treat a conflict as "already there, update it instead".

## Keeping it in step

**On create or update in your system**, push the contact. Small, immediate, no
batch window.

**Don't push your whole database.** Contacts you never call cost you nothing to
leave out, and a contact gets created automatically from an inbound call anyway —
the sync is about adding the *name*, not the existence.

**When someone is deleted on your side**, delete them here too. Their calls stay,
with the personal details removed. See [Contacts](/contacts).

## Reading back

`GET /api/contacts` filters by source, by campaign, by whether they have an email
or phone, and by when they were last seen — so "everyone who called in the last
30 days and isn't in my CRM" is one request.


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