# APAC PQL ↔ HubSpot Writeback

Notes on the two data flows between the APAC PQL model and HubSpot: the model reading the target account list for P0 override, and the model writing score results back to HubSpot for Ops to use. For syncing with Engineering and Ops.

## Background

- HubSpot has a target account segment (`objectLists/19544`). Any domain in this list is escalated to P0 regardless of sales owner assignment or other rules.
- After scoring, the model writes P0/P1/P2 back to a HubSpot contact property, which Ops uses to trigger emails via HubSpot workflows / dynamic lists.

## Service Keys

| Key name | Purpose | Scopes | Used by |
|---|---|---|---|
| `APAC PQL Screening` | Read target account list (19544) membership for P0 override | `crm.lists.read`, `crm.objects.contacts.read` ， `crm.objects.companies.read`  | PQL model sync job |
| `APAC PQL Writeback` | Write P0/P1/P2 score results; write email/track status after Ops sends | `crm.objects.contacts.write`, `crm.objects.contacts.read` | PQL bot and Selva's agent |

## HubSpot Property

- **Object**: Contact properties
- **Property label**: APAC PQL Priority Tier
- **Internal name**: `apac_pql_priority_tier`
- **Field type**: Dropdown select
- **Options**: `P0` / `P1` / `P2` / `Not Scored`
- **Data Agent prompt**: unchecked

## Write Contract for Engineering

```python
import requests

HUBSPOT_TOKEN = "..."
BASE_URL = "https://api.hubapi.com/crm/v3/objects/contacts/batch/upsert"

def write_pql_tier(email_to_tier: dict):
    """
    email_to_tier: {"a@x.com": "P0", "b@y.com": "P1"}
    """
    inputs = [
        {
            "idProperty": "email",
            "id": email,
            "properties": {"apac_pql_priority_tier": tier}
        }
        for email, tier in email_to_tier.items()
    ]

    resp = requests.post(
        BASE_URL,
        headers={"Authorization": f"Bearer {HUBSPOT_TOKEN}"},
        json={"inputs": inputs}
    )
    resp.raise_for_status()
    return resp.json()
```

List read should target list ID 19544 only.

## Sync Note for Ops (draft)

> Hi team, PQL priority now syncs into HubSpot via a Contact property:
> - `APAC PQL Priority Tier` (internal name: `apac_pql_priority_tier`), values P0 / P1 / P2 / Not Scored
>
> Email workflows / dynamic lists can filter on `apac_pql_priority_tier`. Data is written by the PQL bot on a [fill in frequency] cadence. Flag early if the field name or values need to change.

## Open Items

- Whether the 19544 list filter is on the contact or company object (determines whether company scopes are needed)
- Model → HubSpot write frequency (daily / higher)
- Failure alerting for the sync job
