Build a platform
Create, find, update and delete profiles, use externalId for your own ids, set a default profile and timezone, and move accounts between profiles.
A profile groups connected accounts under one brand, client or customer. Every workspace starts with a default profile. Add as many more as you need: profiles are free, and only connected accounts are billed.
#Create a profile
name is required. Everything else is optional.
curl -X POST https://api.pozy.ai/v1/profiles \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Northwind Coffee",
"description": "Retail client, three locations",
"color": "#7C3AED",
"externalId": "client_204"
}'const res = await fetch("https://api.pozy.ai/v1/profiles", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Northwind Coffee",
description: "Retail client, three locations",
color: "#7C3AED",
externalId: "client_204",
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.profile._id);import os, requests
resp = requests.post(
"https://api.pozy.ai/v1/profiles",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
json={
"name": "Northwind Coffee",
"description": "Retail client, three locations",
"color": "#7C3AED",
"externalId": "client_204",
},
)
print(resp.json()["profile"]["_id"]){
"message": "Profile created successfully",
"profile": {
"_id": "6722b8e05d1f4a97c3e2b018",
"name": "Northwind Coffee",
"description": "Retail client, three locations",
"color": "#7C3AED",
"timezone": null,
"externalId": "client_204",
"isDefault": false,
"accountCount": 0,
"createdAt": "2026-10-30T11:20:05.000Z"
}
}| Field | Notes |
|---|---|
name |
Required. Shown in the dashboard and in connect screens you brand. |
description |
Free text for your team. |
color |
Hex colour used to tell profiles apart in the dashboard. |
externalId |
Your own id for this profile, up to 255 characters. Unique in the workspace. |
isDefault |
Set true to make this the workspace's default profile. |
#Use externalId
externalId is how you tie a Pozy profile to a record in your system: a customer id, a tenant slug, a client code. It pays off in three places:
- Lookups.
GET /v1/profiles?externalId=client_204returns that profile, so you never have to store the Pozy id if you prefer not to. - Retries. A second create with the same
externalIdreturns409withcode: "profile_external_id_conflict"anddetails.existingProfileId. Treat it as "already done" and carry on with that id. - Webhooks. Every event lists the profiles it concerns as
profiles: [{ "id", "externalId" }], so your handler can route without a database query (route webhooks).
{
"error": "A profile with this externalId already exists.",
"type": "invalid_request_error",
"code": "profile_external_id_conflict",
"details": { "existingProfileId": "6722b8e05d1f4a97c3e2b018" }
}You can set, change or clear externalId later with an update. Clearing it (null) frees the value for another profile.
#List and find profiles
GET /v1/profiles returns every profile in the workspace, the default first. Filter with name or externalId (both exact matches).
curl "https://api.pozy.ai/v1/profiles?externalId=client_204" \
-H "Authorization: Bearer $POZY_API_KEY"const res = await fetch("https://api.pozy.ai/v1/profiles?externalId=client_204", {
headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
const profile = data.profiles[0]; // undefined when there is no matchresp = requests.get(
"https://api.pozy.ai/v1/profiles",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
params={"externalId": "client_204"},
)
profiles = resp.json()["profiles"]A profile-scoped API key only ever sees the profiles it was given.
#Update a profile
PUT /v1/profiles/{profileId} changes only the fields you send. It also takes timezone, an IANA name such as Europe/Vienna, stored as the profile's default timezone.
curl -X PUT https://api.pozy.ai/v1/profiles/6722b8e05d1f4a97c3e2b018 \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "Northwind Coffee Co.", "timezone": "Europe/Vienna" }'Send "isDefault": true to make a profile the default. The previous default loses the flag.
#The default profile
There is always exactly one default profile, flagged isDefault: true and listed first. The dashboard opens on it. If you delete it, another profile becomes the default.
Keep the default for your own brand's accounts and give each customer their own profile next to it.
#Move an account to another profile
Accounts can change profile without reconnecting, for example when two clients merge or you reorganise brands. Send the target profileId to PATCH /v1/accounts/{accountId}:
curl -X PATCH https://api.pozy.ai/v1/accounts/6720f41a8d3be96c1e5a02f7 \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "profileId": "6722b8e05d1f4a97c3e2b018" }'const res = await fetch("https://api.pozy.ai/v1/accounts/6720f41a8d3be96c1e5a02f7", {
method: "PATCH",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ profileId: "6722b8e05d1f4a97c3e2b018" }),
});
if (!res.ok) throw new Error((await res.json()).error);requests.patch(
"https://api.pozy.ai/v1/accounts/6720f41a8d3be96c1e5a02f7",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
json={"profileId": "6722b8e05d1f4a97c3e2b018"},
)With a profile-scoped key, the target profile must be in the key's scope.
#Delete a profile
curl -X DELETE https://api.pozy.ai/v1/profiles/6722b8e05d1f4a97c3e2b018 \
-H "Authorization: Bearer $POZY_API_KEY"- A profile that still has active connected accounts cannot be deleted. Disconnect them first with
DELETE /v1/accounts/{accountId}. - Disconnected accounts and WhatsApp numbers still in the profile move to another of your profiles. They are never deleted along with it.
- Deleting is permanent. The
externalIdbecomes free for reuse. - API keys scoped to only this profile stop being useful. Revoke them (tenant keys).
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/profiles |
List profiles |
POST /v1/profiles |
Create profile |
GET /v1/profiles/{profileId} |
Get profile |
PUT /v1/profiles/{profileId} |
Update profile |
DELETE /v1/profiles/{profileId} |
Delete profile |