Build a platform
Issue an API key per customer that only reaches their profile, make it read-only or bar whole areas of the API, and rotate it without downtime.
Your main backend can use one full-access key for every customer. Some parts of your system should not: a worker that runs customer-supplied automations, a reporting export, an AI agent acting for one tenant, a script you hand to an agency. Give those a key scoped to one customer's profile, so the worst a bug or a leak can do is limited to that customer.
#Create a key for one customer
Call POST /v1/api-keys with scope: "profiles" and the customer's profile id. Use your full-access, read-write key for this call: scoped and read-only keys cannot create keys.
curl -X POST https://api.pozy.ai/v1/api-keys \
-H "Authorization: Bearer $POZY_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "cus_8f3a2 scheduler",
"scope": "profiles",
"profileIds": ["6720f3b1c9e4a85d2f0b7c14"],
"disabledResourceGroups": ["ads", "telephony", "money", "billing", "webhooks", "commerce", "creator_campaigns"]
}'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: "cus_8f3a2 scheduler",
scope: "profiles",
profileIds: [customer.pozyProfileId],
disabledResourceGroups: ["ads", "telephony", "money", "billing", "webhooks", "commerce", "creator_campaigns"],
}),
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
await secrets.put(`pozy/${customer.id}`, 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": "cus_8f3a2 scheduler",
"scope": "profiles",
"profileIds": ["6720f3b1c9e4a85d2f0b7c14"],
"disabledResourceGroups": ["ads", "telephony", "money", "billing", "webhooks", "commerce", "creator_campaigns"],
},
)
key = resp.json()["apiKey"]["key"] # shown once: store it in your secret managerStore the returned key in your secret manager straight away. It is never shown again; lists only include keyPreview.
A key can cover several profiles. A customer with two brands can get one key with both profile ids.
#Pick the right restrictions
Combine the three controls to match the job:
| Job | scope |
permission |
disabledResourceGroups |
|---|---|---|---|
| Post scheduler for one customer | profiles |
read-write |
everything except publishing and accounts |
| Customer-facing analytics dashboard | profiles |
read |
messages, contacts, billing, webhooks, money |
| Support inbox for one customer | profiles |
read-write |
everything except messages, engagement, contacts, accounts |
| AI assistant that only reads | profiles |
read |
billing, money, webhooks |
| Short-lived access for a contractor | profiles |
as needed | as needed, plus expiresIn: 7 |
The full list of groups and what each covers is in Authentication.
#What a scoped key can and cannot do
A profile-scoped key:
- Can do anything its permission and groups allow, as long as every
profileIdin the request is in its scope. - Gets
403withcode: "profile_out_of_scope"when a request names any other profile. - Gets
403withcode: "account_out_of_scope"when a request names an account that lives in any other profile, for example anaccountIdin a post'splatforms. - Sees only its own profiles in
GET /v1/profiles. - Can move an account only into a profile in its scope.
- Cannot list, create or delete API keys (
403,code: "insufficient_permissions"). - Cannot read workspace-wide billing or usage (
403,code: "profile_scoped_key"), but can read usage for its own profile withGET /v1/usage?profileId=....
Pass the customer's profileId on every list call made with a scoped key, such as accounts, posts, conversations and analytics. It keeps results inside the tenant and makes the scope check explicit.
#Rate limits are shared
Scoped keys do not add throughput. Every key in the workspace draws from the same per-minute budget (rate limits). If one customer runs a large import, queue it on your side so it cannot use up the budget your other customers need.
#Rotate a customer's key
There is no update endpoint for keys. To change a key's settings or rotate it:
- Create a new key with the settings you want.
- Switch the customer's service to it.
- Delete the old key with
DELETE /v1/api-keys/{keyId}.
Deleting takes effect on the next request. Keep the key id next to the stored secret so you can revoke the right one later.
#Clean up
When a customer leaves, revoke their keys as part of offboarding (build a platform). Use GET /v1/api-keys to find keys whose profileIds include the profile you are deleting.
#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 |