Ads
Build customer lists, lookalikes, website, engagement and company audiences on each ad network, upload hashed members and target them.
An audience is a set of people you target or exclude. Some you fill yourself by uploading emails (customer lists). Others the network fills from a pixel, a seed list or engagement with your Page or videos. Create every type with POST /v1/ads/audiences, then put its platformAudienceId in audienceInclude or audienceExclude on a create.
#Upload a customer list
#Create the audience
curl -X POST https://api.pozy.ai/v1/ads/audiences \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"adAccountId": "act_1234567890",
"name": "Customers - last 12 months",
"type": "customer_list",
"description": "Paid at least once since November 2025"
}'const res = await fetch("https://api.pozy.ai/v1/ads/audiences", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
accountId: "66b2e19d8c3f5a7e9d0b1c2d",
adAccountId: "act_1234567890",
name: "Customers - last 12 months",
type: "customer_list",
description: "Paid at least once since November 2025",
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
const audienceId = data.audience.id;import os, requests
resp = requests.post(
"https://api.pozy.ai/v1/ads/audiences",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
json={
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"adAccountId": "act_1234567890",
"name": "Customers - last 12 months",
"type": "customer_list",
"description": "Paid at least once since November 2025",
},
)
audience_id = resp.json()["audience"]["id"]Creates are not idempotent. Do not retry one automatically: list the audiences first to see whether it exists.
#Upload members
Send plaintext email (and on Meta, phone in E.164) per row, up to 10,000 rows per request.
curl -X POST https://api.pozy.ai/v1/ads/audiences/66e5b2c3d4f5a6b7c8d9e0f1/users \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "users": [ { "email": "maria@example.com" }, { "email": "sam@example.org", "phone": "+14155551234" } ] }'{ "message": "Users added", "numReceived": 2, "numInvalid": 0 }#Target it
Read platformAudienceId from GET /v1/ads/audiences?accountId=...&adAccountId=... and send it in audienceInclude or audienceExclude on POST /v1/ads/create.
#Hashing and matching
You send plain values. Pozy normalizes them (trims, lowercases emails, formats phones) and hashes them with SHA-256 before they leave Pozy, so the networks never receive raw contact details. You do not need to hash anything yourself.
| Network | Matches on | Per request | Upload behavior | Notes |
|---|---|---|---|---|
| Meta | Email and phone | 10,000 | Adds | Remove people with DELETE /v1/ads/audiences/{audienceId}/users (Meta only). |
| Google (Customer Match) | 10,000 | Adds | Matching takes 10 minutes to 24 hours. Google only serves a list once enough members match; upload at least 5,000. | |
| TikTok | 10,000 | Adds | Created on TikTok with the first upload. Takes up to 48 hours before it can be targeted. | |
| 10,000 | Replaces the whole list | Every upload is the full list, so a contact list tops out at 10,000 members. | ||
| 10,000 | Adds | Created on Pinterest with the first upload. | ||
| X (Tailored Audiences) | 10,000 | Adds | Needs at least 100 matched active users before it can be targeted; size reads 0 until then. | |
| – | – | – | Build custom audiences in Reddit Ads Manager and target them by id. Creates return 422. |
|
| ChatGPT | – | – | – | No custom audiences. |
A phone on a network that matches on email only is ignored. A row that cannot be read counts in numInvalid.
Only upload people who agreed to be contacted this way. Each network's terms for customer lists apply to you, and the hashed upload does not change that.
#Audience types
type on POST /v1/ads/audiences picks what the audience is built from.
type |
Network | Built from | Key fields |
|---|---|---|---|
customer_list |
Meta, Google, TikTok, LinkedIn, Pinterest, X | Emails (and phones on Meta) you upload | customerFileSource on Meta |
lookalike |
Meta | People similar to a seed audience | sourceAudienceId (the seed's platformAudienceId), country, ratio 0.01 to 0.2 |
website |
Meta | Pixel visitors | pixelId, retentionDays, optional urlContains or a raw Meta rule |
meta_engagement |
Meta | People who engaged with a Page, an Instagram account or a video | engagementSource (page, instagram, video), sourceId, retentionDays 1 to 365, optional event |
saved_targeting |
Meta | A stored targeting spec, no members | spec. Use it later as savedTargetingId. |
company_list |
Companies by name, domain, website or Page URL | companies (up to 300,000 rows, at least 1,000 recommended) |
|
engagement |
People who engaged with ads, Pages or events | sourceType, trigger, lookbackDays (30 to 365), engagementSources (up to 50) |
|
website_retargeting |
Insight Tag visitors matching URL rules | matchRules with matchType (EXACT, STARTS_WITH, CONTAINS, ENDS_WITH), up to 50 rules |
|
tiktok_engagement |
TikTok | People who engaged with your ads or videos | source, sourceIds, identityId |
pinterest_engagement |
People who engaged with your Pins | engagementType, pinIds |
Using a type on the wrong network's account returns 422. Meta's meta_engagement and LinkedIn's engagement are different audiences with different fields.
#Lookalikes on Meta
Upload members to the seed list first, then create the lookalike from it. Meta builds it from the seed's matched members, so check the seed's size with GET /v1/ads/audiences/{audienceId} before you create. ratio: 0.01 is the closest 1% of the country.
{
"accountId": "66b2e19d8c3f5a7e9d0b1c2d",
"adAccountId": "act_1234567890",
"name": "Lookalike 1% US - customers",
"type": "lookalike",
"sourceAudienceId": "23851234567890123",
"country": "US",
"ratio": 0.01
}#LinkedIn company lists
Company lists target or exclude whole companies. Each row needs at least one of name, domain, website or linkedinPageUrl. LinkedIn matches rows against its company graph within 48 hours. To change the list, send the complete new list to POST /v1/ads/audiences/{audienceId}/companies: it replaces the old one.
#LinkedIn website retargeting
The audience fills only once the site has the LinkedIn Insight Tag installed and reporting visits (Pixels and tags). You can create it before the tag is live.
#Manage audiences
| Job | Call |
|---|---|
| List with size and status | GET /v1/ads/audiences?accountId=...&adAccountId=... |
| Read one with fresh numbers | GET /v1/ads/audiences/{audienceId} |
| Rename or edit | PUT /v1/ads/audiences/{audienceId} (name and description; spec only on saved targeting) |
| Delete | DELETE /v1/ads/audiences/{audienceId} |
audience.id is Pozy's id, used in the paths above. platformAudienceId is the network's id, used in targeting and as a lookalike seed. Audiences build asynchronously on every network: a size or member read right after an upload can be empty. Read again after a minute instead of uploading again.
#Errors
| Error | Cause | Fix |
|---|---|---|
422 on /users |
The audience is not a customer_list (or is a LinkedIn company list) |
Upload rows only to customer lists. Company lists use /companies. |
422 "Audience has no platform ID" |
The network has not accepted the audience yet | Read it again and retry once platformAudienceId is set. |
422 on create |
The type does not exist on that network | Use a type from the table above. |
400 with type: "platform_error" |
The network rejected a rule or source (for example an ineligible engagement source on Meta) | Read the network's message in platformError. |
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/ads/audiences |
List custom audiences |
POST /v1/ads/audiences |
Create custom audience |
GET /v1/ads/audiences/{audienceId} |
Get audience details |
PUT /v1/ads/audiences/{audienceId} |
Update an audience |
DELETE /v1/ads/audiences/{audienceId} |
Delete custom audience |
POST /v1/ads/audiences/{audienceId}/users |
Add users to audience |
DELETE /v1/ads/audiences/{audienceId}/users |
Remove users from audience |
POST /v1/ads/audiences/{audienceId}/companies |
Replace audience companies |