CrystalQore
DevelopersRecipes

Sync contacts

Create CrystalQore contacts from your CRM and list them back for reconciliation.

Sync contacts

Push people from a CRM into CrystalQore so agents can click-to-dial and see a name on the call.

Create

POST /api/v1/contacts requires X-User-Email. Pick a service mailbox or the owner who should see the contact in CrystalQore.

import os
import requests
 
HEADERS = {
    "X-API-Key": os.environ["CRYSTALQORE_API_KEY"],
    "X-Tenant-Id": os.environ["CRYSTALQORE_TENANT_ID"],
    "X-User-Email": os.environ["CRYSTALQORE_USER_EMAIL"],
}
 
def upsert_contact(record):
    created = requests.post(
        "https://app.crystalqore.com/api/v1/contacts",
        headers=HEADERS,
        json={
            "firstName": record["first_name"],
            "lastName": record.get("last_name", ""),
            "company": record.get("company"),
            "phoneWork": record.get("phone"),
            "email": record.get("email") or "",
            "notes": f"CRM id {record['id']}",
        },
        timeout=30,
    )
    created.raise_for_status()
    return created.json()["data"]["contact"]

The v1 API does not update by external ID. Store data.contact.id in your CRM after create. If you need idempotency, list first and skip names you already pushed.

List for reconciliation

def list_contacts(search=None):
    params = {"type": "all", "limit": 100, "offset": 0}
    if search:
        params["search"] = search
    r = requests.get(
        "https://app.crystalqore.com/api/v1/contacts",
        headers={
            "X-API-Key": os.environ["CRYSTALQORE_API_KEY"],
            "X-Tenant-Id": os.environ["CRYSTALQORE_TENANT_ID"],
        },
        params=params,
        timeout=30,
    )
    r.raise_for_status()
    return r.json()

Walk meta.pagination.hasMore as described in pagination. Sending X-User-Email on GET limits results to that owner's contacts.

On this page