Getting started
Authenticate with API keys, limit them to some profiles, make them read-only or bar whole areas of the API, and rotate them safely.
Every request to https://api.pozy.ai/v1 carries a bearer credential in the Authorization header. For your own servers that credential is an API key. The MCP server signs in with OAuth, and the dashboard uses your browser session. All of them hit the same API with the same rules.
curl https://api.pozy.ai/v1/accounts \
-H "Authorization: Bearer $POZY_API_KEY"#API keys
A key looks like pz_live_ followed by 64 hex characters. It belongs to the workspace, not to the person who created it, so it keeps working when that member leaves.
Pozy stores only a SHA-256 hash of each key. The full value is returned once, when you create it. Lists show a preview such as pz_live_3f9a...c41e so you can tell keys apart.
A key can do anything its settings allow, including publishing and spending money on ads, numbers and messages. Never ship one in a mobile app, a browser bundle or a public repository. If one leaks, delete it at once and create a new one.
#Create a key in the dashboard
Open API keys, click Create key, pick a name and the settings below, and copy the value. Workspace owners and admins can create keys.
#Create a key with the API
POST /v1/api-keys creates a key from code, for example when you onboard a customer and want a key that only reaches their profile. The call needs a full-access, read-write key (or an owner or admin session).
curl -X POST https://api.pozy.ai/v1/api-keys \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Reporting job",
"permission": "read",
"disabledResourceGroups": ["billing", "webhooks"],
"expiresIn": 90
}'const res = await fetch("https://api.pozy.ai/v1/api-keys", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.POZY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "Reporting job",
permission: "read",
disabledResourceGroups: ["billing", "webhooks"],
expiresIn: 90,
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
console.log(data.apiKey.key); // shown onceimport os, requests
resp = requests.post(
"https://api.pozy.ai/v1/api-keys",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
json={
"name": "Reporting job",
"permission": "read",
"disabledResourceGroups": ["billing", "webhooks"],
"expiresIn": 90,
},
)
print(resp.json()["apiKey"]["key"]) # shown once{
"message": "API key created",
"apiKey": {
"id": "key_Vb3nQ8rT1xLm6Zc0Wp9s",
"name": "Reporting job",
"key": "pz_live_3f9a0c7e...",
"keyPreview": "pz_live_3f9a...c41e",
"scope": "full",
"profileIds": [],
"permission": "read",
"disabledResourceGroups": ["billing", "webhooks"],
"expiresAt": "2027-01-28T10:12:44.000Z",
"createdAt": "2026-10-30T10:12:44.000Z"
}
}#Key settings
| Field | Values | Default | Effect |
|---|---|---|---|
name |
text | required | Label shown in lists and logs. |
scope |
full, profiles |
full |
profiles limits the key to the profiles in profileIds. |
profileIds |
profile ids | none | Required when scope is profiles. Every id must belong to the workspace. |
permission |
read-write, read |
read-write |
read allows only GET requests. |
disabledResourceGroups |
group names | none | Areas of the API the key may not call. See the table below. |
expiresIn |
days | never expires | The key stops working after that many days. |
#Profile-scoped keys
A key with scope: "profiles" is limited to the profiles you list. Any request that names a profile outside that list, in the path, the query string or the body, fails with 403 and code: "profile_out_of_scope". A request that names an account (accountId, accountIds, targetAccountId or sourceAccountId) belonging to another profile fails with 403 and code: "account_out_of_scope". GET /v1/profiles returns only the profiles in scope.
Use one per customer when you build a platform, so a bug or a leaked key in one tenant cannot touch another. With a scoped key, always pass profileId on list calls (accounts, posts, conversations) so results stay inside the tenant.
Scoped keys cannot manage API keys, and they cannot read workspace-wide billing. Calls that need the whole workspace return 403 with code: "profile_scoped_key".
#Read-only keys
With permission: "read", any request other than GET fails before it runs:
{
"error": "This credential is read-only.",
"type": "permission_error",
"code": "read_only_key"
}Give read-only keys to dashboards, reporting jobs, BI tools and AI assistants that only need to look.
#Disabled resource groups
Every endpoint belongs to one resource group. A key with a group in disabledResourceGroups gets 403 with code: "resource_group_disabled" on any endpoint in that group, read or write.
| Group | Covers |
|---|---|
publishing |
Posts, queues, validation tools, media uploads, blog articles |
engagement |
Comments, reviews, mentions, likes and reposts, Discord server actions, Google Business reviews |
messages |
DMs and conversations, broadcasts, sequences, comment-to-DM, WhatsApp and RCS messages, email, voice agents |
contacts |
Contacts, custom field values, ad lead forms and leads, WhatsApp blocked users |
analytics |
Post, account and inbox analytics |
ads |
Ad accounts, campaigns, ad sets, creatives, audiences, conversions, pixels, catalogs, rules, insights |
telephony |
Phone numbers, SMS, voice calls, branded calling, WhatsApp numbers and calling, verification codes |
accounts |
Connect flows, connected accounts, profiles, account groups, account settings, workflows, WhatsApp templates and flows, Google Business locations |
billing |
Usage and billing |
webhooks |
Webhook endpoints, delivery logs, test deliveries |
commerce |
Stores, products, orders and other commerce data |
creator_campaigns |
Creator campaigns, participants and submissions |
money |
Balance, top-ups, payees and transfers |
calendar |
Calendar events |
files |
Files |
The API reference shows each endpoint's group under Authentication.
Start from the narrowest key that works. A scheduling backend needs publishing and accounts, so it can disable ads, telephony, money, billing and webhooks. A support inbox needs messages, engagement and contacts.
#Rotate and revoke keys
Deleting a key revokes it immediately. Requests that use it start failing with 401 on the next call.
To rotate without downtime:
- Create the new key with the same settings.
- Deploy it everywhere the old key is used.
- Check the old key's Last used time in the dashboard. Once it stops moving, delete it.
curl -X DELETE https://api.pozy.ai/v1/api-keys/key_Vb3nQ8rT1xLm6Zc0Wp9s \
-H "Authorization: Bearer $POZY_API_KEY"const res = await fetch("https://api.pozy.ai/v1/api-keys/key_Vb3nQ8rT1xLm6Zc0Wp9s", {
method: "DELETE",
headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
if (!res.ok) throw new Error((await res.json()).error);requests.delete(
"https://api.pozy.ai/v1/api-keys/key_Vb3nQ8rT1xLm6Zc0Wp9s",
headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
)#Check a credential
GET /v1/auth/verify returns valid: true with the credential type (api_key, oauth or session), its scope and the workspace it belongs to. Use it in health checks and when you debug a 401 or 403.
#OAuth for the MCP server
The MCP server at https://mcp.pozy.ai/mcp signs you in through the browser with your Pozy account. It acts as you, so your workspace role applies: a viewer gets read-only access, and a member cannot manage keys, webhooks or billing. You can revoke these sessions from Settings → Connected apps in the dashboard. Clients that cannot do OAuth can send an API key as the bearer token instead.
#Dashboard sessions
The dashboard calls the same public API with your session cookie. Write requests from another site are refused with code: "csrf_rejected", so a session cannot be used from a page you do not trust. Dashboard traffic has its own rate limit budget, 120 requests a minute per workspace, and does not eat into your keys' limit.
#Errors you may see
| Status | code |
Meaning | Fix |
|---|---|---|---|
| 401 | invalid_api_key |
Missing, mistyped, revoked or expired credential. | Check the Authorization: Bearer header and the key's expiry. |
| 403 | read_only_key |
A write with a read-only key. | Use a read-write key. |
| 403 | resource_group_disabled |
The endpoint's group is disabled on this key. | Use a key that allows the group. |
| 403 | insufficient_permissions |
The key type cannot do this, for example a scoped or read-only key managing keys. | Use a full-access, read-write key. |
| 403 | role_forbidden |
Your workspace role cannot do this (sessions and OAuth tokens). | Ask an owner or admin for a different role. |
| 403 | profile_out_of_scope |
A profile-scoped key named a profile it does not cover. | Use a key scoped to that profile. |
| 403 | account_out_of_scope |
A profile-scoped key named an account that belongs to another profile. | Check the account id, or use a key scoped to that account's profile. |
| 403 | profile_scoped_key |
A profile-scoped key called a workspace-wide endpoint. | Pass a profileId where the endpoint accepts one, or use a full-access key. |
| 403 | feature_not_available |
The feature is not enabled for the workspace. | Contact support@pozy.ai. |
#Endpoints
| Endpoint | What it does |
|---|---|
GET /v1/auth/verify |
Verify credential |
GET /v1/api-keys |
List keys |
POST /v1/api-keys |
Create key |
DELETE /v1/api-keys/{keyId} |
Delete key |