Audience Syncs
Audience syncs push a graph8 audience (contact list) to an ad platform and keep it in sync on a cadence. graph8 supports four platforms: Meta (Facebook/Instagram custom audiences), LinkedIn (Matched Audiences), Google Ads (Customer Match), and X (Tailored Audiences).
Each sync config has a mode:
mirror- keep the platform audience exactly in sync with the source list (adds new members, removes dropped members).append_only- only add new members; never remove.
A worker re-runs each sync on its refresh_cadence_hours. You can also trigger a sync manually.
| Endpoint | Method | Description |
|---|---|---|
/audience-syncs | GET | List all sync configs for the org |
/audience-syncs | POST | Create a new sync config |
/audience-syncs/{id} | GET | Get a single sync config |
/audience-syncs/{id} | PATCH | Update a sync config |
/audience-syncs/{id} | DELETE | Soft delete a sync config |
/audience-syncs/{id}/trigger | POST | Manually trigger a sync run |
/audience-syncs/{id}/runs | GET | List recent sync runs |
/audience-syncs/{id}/errors | GET | List failed sync runs only |
For machine-readable schemas see the interactive API docs.
List Audience Syncs
GET /audience-syncs
Returns every sync config for the authenticated org.
Example
curl "https://be.graph8.com/api/v1/audience-syncs" \ -H "Authorization: Bearer $API_KEY"response = requests.get( f"{BASE_URL}/audience-syncs", headers=HEADERS,)configs = response.json()["data"]Response
{ "data": [ { "id": 12, "audience_id": 5, "platform": "meta", "platform_audience_name": "Q2 Outbound - Mirror", "mode": "mirror", "refresh_cadence_hours": 24, "is_active": true, "status": "active", "last_sync_at": "2026-04-15T08:00:00Z", "created_at": "2026-04-01T10:00:00Z" } ]}Create Audience Sync
POST /audience-syncs
Create a new sync config. Returns 409 Conflict if a config already exists for the same audience_id + platform.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
audience_id | integer | Yes | Source list ID (must be > 0) |
platform | string | Yes | One of meta, linkedin, google, x |
platform_audience_name | string | No | Display name on the ad platform (max 255) |
mode | string | No | mirror (default) or append_only |
refresh_cadence_hours | integer | No | 0-720, default 24 |
platform_config | object | No | Platform-specific config (e.g. ad account ID, OAuth scopes) |
suppression_list_ids | integer[] | No | Lists whose members should be excluded |
Example
curl -X POST "https://be.graph8.com/api/v1/audience-syncs" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{ "audience_id": 5, "platform": "meta", "platform_audience_name": "Q2 Outbound", "mode": "mirror", "refresh_cadence_hours": 24, "platform_config": {"ad_account_id": "act_1234567890"} }'response = requests.post( f"{BASE_URL}/audience-syncs", headers=HEADERS, json={ "audience_id": 5, "platform": "meta", "platform_audience_name": "Q2 Outbound", "mode": "mirror", "refresh_cadence_hours": 24, "platform_config": {"ad_account_id": "act_1234567890"}, },)Response 201 Created
Returns the same shape as a list item.
Errors
| Status | Meaning |
|---|---|
409 | A sync config already exists for this audience + platform |
422 | platform not in allowed set, or mode invalid |
Get Audience Sync
GET /audience-syncs/{config_id}
Returns a single sync config by ID.
Example
curl "https://be.graph8.com/api/v1/audience-syncs/12" \ -H "Authorization: Bearer $API_KEY"Errors
| Status | Meaning |
|---|---|
404 | Sync config not found |
Update Audience Sync
PATCH /audience-syncs/{config_id}
Partial update. Send only the fields you want to change.
Request Body
| Field | Type | Description |
|---|---|---|
mode | string | mirror or append_only |
refresh_cadence_hours | integer | 0-720 |
is_active | boolean | Pause/unpause without deleting |
suppression_list_ids | integer[] | Replace suppression list set |
Example
curl -X PATCH "https://be.graph8.com/api/v1/audience-syncs/12" \ -H "Authorization: Bearer $API_KEY" \ -H "Content-Type: application/json" \ -d '{"is_active": false}'Delete Audience Sync
DELETE /audience-syncs/{config_id}
Soft delete. The platform audience is not removed from the ad platform - graph8 simply stops syncing.
Response
{ "data": { "status": "deleted", "id": 12 } }Trigger Audience Sync
POST /audience-syncs/{config_id}/trigger
Run the sync immediately, outside of its scheduled cadence. Returns the sync result payload (members added/removed counts).
Example
curl -X POST "https://be.graph8.com/api/v1/audience-syncs/12/trigger" \ -H "Authorization: Bearer $API_KEY"Errors
| Status | Meaning |
|---|---|
500 | Underlying ad platform returned an error - check /runs or /errors for the message |
List Sync Runs
GET /audience-syncs/{config_id}/runs
Returns recent runs for a config (success and failure both).
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 20 | Max runs to return (1-100) |
Response
{ "data": [ { "id": 4521, "started_at": "2026-04-15T08:00:00Z", "finished_at": "2026-04-15T08:00:14Z", "status": "success", "members_added": 12, "members_removed": 3, "total_members": 1450, "error_message": null } ]}List Sync Errors
GET /audience-syncs/{config_id}/errors
Same shape as /runs, filtered to status = "failed". Use this when surfacing failures in your dashboard.
Query Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
limit | integer | 20 | Max errors to return (1-100) |
Response
{ "data": [ { "id": 4520, "started_at": "2026-04-15T07:30:00Z", "error_message": "Meta API: invalid access token", "details": { "config_id": 12, "status": "failed" } } ]}