Metadata-Version: 2.4
Name: contackd-sync
Version: 0.4.1
Summary: Sync CRM records and capture immutable person and business events with the Contackd API
Project-URL: Homepage, https://example.com/contackd-sync
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Python: >=3.9
Description-Content-Type: text/markdown
Requires-Dist: requests>=2.31.0
Requires-Dist: urllib3>=1.26.20

# contackd-sync (Python)

Python SDK for syncing CRM records (`contacts`, `leads`, `prospects`, and `businesses`), managing deals, and capturing immutable person and business events.

Requires Python 3.9 or later.

## Install

```bash
pip install contackd-sync
```

## 2-Minute Start (Push Customer Details)

```python
from contackd_sync import ContackdClient, Contact

client = ContackdClient(
    api_key="sk_live_...",
    base_url="https://api.yourapp.com/api/v1",  # no trailing slash required
)

# Create/update a customer contact by email
customer = client.contacts.upsert(
    Contact(
        email="jane@acme.com",
        first_name="Jane",
        last_name="Doe",
        phone="+14155550199",
        tags=["customer", "vip"],
        custom={
            "customer_id": "CUST-1001",
            "plan": "pro",
            "country": "US",
        },
    )
)

print(customer)
```

## Capture Custom Events

```python
from contackd_sync import PersonEvent

event = client.person_events.track(
    PersonEvent(
        unified_id=customer.id,
        event_name="financing",
        status="applied",
        correlation_id="application-10042",
        amount="10000.00",
        currency="NGN",
    )
)

current_states = client.person_events.latest(customer.id)
```

Use `BusinessEvent` with `client.business_events` for B2B actions. Both event resources expose `track`, `track_batch`, `list`, and `latest`; a retry-safe `event_id` is generated when omitted.

## Manage Deals

```python
from contackd_sync import Deal, DealStage, DealTransaction

deal = client.deals.create(
    Deal(
        contact_id=customer.id,
        title="Annual facility management plan",
        amount="150000.00",
        currency="NGN",
    )
)

client.deals.update(deal.id, assigned_to_user_id="sales-agent-id")
won = client.deals.update_stage(
    deal.id,
    DealStage.WON,
    transaction=DealTransaction(external_transaction_id="payment-10042"),
)
```

`client.deals` also provides `get` and `list`. List filters include
`contact_id`, `lead_id`, `conversation_id`, `stage`, `q`, and
`assigned_to_user_id`.

## Common Customer Push Patterns

### 1) Push one new customer

```python
from contackd_sync import Contact

created = client.contacts.create(
    Contact(email="new@acme.com", first_name="New", last_name="Customer")
)
```

### 2) Push many customers (bulk upsert)

```python
from contackd_sync import Contact

result = client.contacts.bulk_upsert(
    [
        Contact(email="a@acme.com", first_name="A"),
        Contact(email="b@acme.com", first_name="B", tags=["trial"]),
    ]
)

print(len(result.created), len(result.updated), result.errors)
```

### 3) Read/filter customers

```python
page = client.contacts.list(page=1, per_page=50, email="jane@acme.com")
```

## Sync Businesses Before Their Contacts

Create or update businesses first so contacts can reference the returned CRM
business IDs. Business synchronization uses `external_business_id` as its
primary natural key and falls back to the normalized business name.

```python
from contackd_sync import Business, Contact, ContackdClient

client = ContackdClient(
    api_key="sk_live_...",
    base_url="https://api.yourapp.com/api/v1",
)

business_result = client.businesses.bulk_upsert(
    [
        Business(
            name="Default Facility",
            external_business_id="bb7d2b66-034a-4333-8573-dce07b9684ed",
            stage="customer",
            status="active",
            tags=["FACILITY"],
            custom={"org_code": "FACILITYBILLS"},
        )
    ]
)
business = [*business_result.created, *business_result.updated][0]

contact_result = client.contacts.bulk_upsert(
    [
        Contact(
            email="resident@example.com",
            first_name="Resident",
            external_contact_id="resident-1",
            business_id=business.id,
            tags=["RESIDENT"],
            custom={"role": "resident"},
        )
    ]
)
```

Callers should merge duplicate source rows before sending them. For a person
belonging to multiple estates, keep the complete estate list in `custom` and
use `business_id` for the single primary CRM relationship.

## API Key Setup

Contact support@dalmlabs.com for the API key and base domain.

## Backend Routes Expected by SDK

Given `base_url = https://api.yourapp.com/api/v1`:

- `GET /health`
- `POST /tags`
- `GET /tags`
- `GET /tags/{id}`
- `PUT /tags/{id}`
- `DELETE /tags/{id}`
- `POST /contacts|leads|prospects|businesses`
- `GET /contacts|leads|prospects|businesses/{id}`
- `PUT /contacts|leads|prospects|businesses/{id}`
- `DELETE /contacts|leads|prospects|businesses/{id}`
- `GET /contacts|leads|prospects|businesses`
- `POST /contacts|leads|prospects|businesses/upsert`
- `POST /contacts|leads|prospects|businesses/bulk`
- `POST /contacts|leads|prospects|businesses/bulk/upsert`
- `POST /contacts|leads|prospects|businesses/bulk/delete`
- `POST /events/person|business`
- `POST /events/person|business/batch`
- `GET /events/person|business/{id}`
- `GET /events/person|business/{id}/latest`
- `POST /deals`
- `GET /deals`
- `GET /deals/{id}`
- `PATCH /deals/{id}`
- `PATCH /deals/{id}/stage`
