Labels & Permissions (IAM v1)
Control who can see and use your integrations, credentials, and knowledge docs using labels. A simple, label-based permission system built for teams.
Labels & Permissions (IAM v1)
HeadlessOps includes a built-in permission system called Label-Based Access Control (or IAM v1). It lets admins control exactly which team members can see and interact with specific resources — without complex role hierarchies.
The idea is simple: you tag resources with labels, then grant members access to those labels. Only members who have a grant for a label can see the resources tagged with it.
Why Labels?
Not every team member should see every integration or credential. A contractor might only need access to one project. A client might need to view their own automations but nothing else. Labels make this easy.
Instead of creating complex per-resource rules, you:
- Assign a label to a resource (e.g.
client-acmeorteam-data) - Grant a team member access to that label
- Done — they can now see and use all resources tagged with that label
How It Works
The Two Permission Levels
When you grant a member access to a label, you choose one of two levels:
| Grant | View resource | Run integration | Edit code & config | Assign/remove this label |
|---|---|---|---|---|
read | ✅ | ✅ | ✅ | ❌ |
write | ✅ | ✅ | ✅ | ✅ |
| ADMIN / OWNER | ✅ | ✅ | ✅ | ✅ |
Both read and write give full access to view, run, and edit resources. The only difference is label management: write holders can also attach or remove that label on resources themselves.
In short:
read= use the resource.write= use the resource AND manage the label on resources.
Unlabeled Resources Are Admin-Only
Any resource that has no labels is invisible to non-admin members. This is the secure default.
If you create a new integration and do not label it, only ADMINs and OWNERs can see it. Once you add a label and grant a member access to that label, they can see it.
This means:
- New resources start private
- You consciously decide who gets access by adding a label
- There is no accidental exposure
How Access Is Checked
When a member tries to access a resource, the system checks in order:
1. Is the member an OWNER or ADMIN? → Yes → Allow
2. Does the resource have any labels? → No → Deny (admin-only)
3. Does the member have a grant for any of the resource's labels? → No → Deny
4. Action is view / run / edit? → Yes → Allow
5. Action is assigning/removing a label?
→ Only if the member has a "write" grant for that specific label → Allow
→ Otherwise → DenyLabels Across Resource Types
You can apply labels to three types of resources:
| Resource | Supports Labels |
|---|---|
| Integrations | ✅ (always supported) |
| Credentials | ✅ (added in IAM v1) |
| Knowledge Docs | ✅ (added in IAM v1) |
A single label grant gives access to all three types. For example, a member with a read grant on client-acme can see all integrations, credentials, and knowledge docs tagged client-acme.
Managing Labels in Settings
Go to Workspace Settings → Labels to manage all labels in your workspace.
From there you can:
- See all labels that exist in your workspace
- Add or edit a label description
- See which members have grants for each label
- Delete labels that are no longer needed
Labels are created automatically the first time you assign one to a resource. You do not need to pre-create them.
Duplicate label names are rejected. If you try to create a label that already exists in the workspace, you'll see: "A label with this name already exists. Please contact your workspace administrator to request access." The existing label is left untouched and no access is granted — this prevents a member from gaining access to a label they can't otherwise see by "recreating" it.
Granting a Member Access to a Label
Only ADMINs and OWNERs can manage label grants.
Via the Web UI
- Go to Workspace Settings → Members
- Click on the member's name
- Under Label Access, click Add Grant
- Type the label name and choose
readorwrite - Optionally set an expiry date/time for a temporary grant (see below)
- Click Save
Via the API
List grants for a member:
curl https://app.headlessops.ai/api/workspaces/ws_abc123/members/mem_xyz/label-grants \
-H "Authorization: Bearer iter_YOUR_KEY"Response:
[
{ "id": "grant_1", "label": "client-acme", "permission": "read", "expiresAt": null },
{ "id": "grant_2", "label": "team-data", "permission": "write", "expiresAt": "2026-07-12T18:00:00.000Z" }
]Add a new grant:
curl -X POST https://app.headlessops.ai/api/workspaces/ws_abc123/members/mem_xyz/label-grants \
-H "Authorization: Bearer iter_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "label": "client-acme", "permission": "read" }'Response:
{
"id": "grant_3",
"label": "client-acme",
"permission": "read",
"expiresAt": null,
"createdAt": "2026-06-01T00:00:00Z"
}Remove a grant:
curl -X DELETE https://app.headlessops.ai/api/workspaces/ws_abc123/members/mem_xyz/label-grants/grant_3 \
-H "Authorization: Bearer iter_YOUR_KEY"Temporary (Expiring) Label Grants
Grants can be time-boxed by setting an expiresAt value. This is useful for short-term contractor access, temporary client demos, or any situation where access should automatically lapse without an admin having to remember to revoke it.
- Leave
expiresAtunset (ornull) for a permanent grant — the default behavior. - Set
expiresAtto a future date/time to make the grant temporary. Once that time passes, the grant is treated as if it does not exist — the member immediately loses read/write access to resources tagged with that label. - Expired grants are not deleted automatically; they simply stop being honored by permission checks. Admins can still see them (e.g. to review history) and can extend or remove them at any time.
Setting an expiry via the API:
curl -X POST https://app.headlessops.ai/api/workspaces/ws_abc123/members/mem_xyz/label-grants \
-H "Authorization: Bearer iter_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "label": "client-acme", "permission": "read", "expiresAt": "2026-07-14T00:00:00Z" }'Both full ISO 8601 datetimes (2026-07-14T00:00:00Z) and the datetime-local format produced by HTML date pickers (2026-07-14T00:00) are accepted.
Via the Web UI: the Add Grant dialog in Workspace Settings → Members includes an optional expiry date/time field. Leave it blank for a permanent grant.
Assigning Labels to Resources
Labels are attached to resources using a PATCH request on the resource. The body is a full replacement — pass the complete list of labels you want the resource to have.
Who can assign labels?
- ADMINs and OWNERs can assign any label to any resource
- A member with a
writegrant on a label can assign or remove only that label on resources
Integrations
curl -X PATCH https://app.headlessops.ai/api/integrations/my-automation/labels \
-H "Authorization: Bearer iter_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "labels": ["client-acme", "production"] }'Credentials
curl -X PATCH https://app.headlessops.ai/api/credentials/cred_abc123/labels \
-H "Authorization: Bearer iter_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "labels": ["client-acme"] }'Knowledge Docs
curl -X PATCH https://app.headlessops.ai/api/knowledge-docs/doc_abc123/labels \
-H "Authorization: Bearer iter_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "labels": ["client-acme"] }'Note: When you assign a label to a resource for the first time, the label is automatically registered in the workspace label registry. No separate setup step is needed.
Label Registry API
The label registry lets you view and manage all labels in your workspace.
List all labels:
curl https://app.headlessops.ai/api/workspaces/ws_abc123/labels \
-H "Authorization: Bearer iter_YOUR_KEY"Response:
[
{ "name": "client-acme", "description": "Acme Corp production integrations" },
{ "name": "team-data", "description": "Data engineering team resources" },
{ "name": "production", "description": null }
]Update a label's description (ADMIN only):
curl -X PUT https://app.headlessops.ai/api/workspaces/ws_abc123/labels/client-acme \
-H "Authorization: Bearer iter_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "description": "All resources for the Acme Corp account" }'Delete a label (ADMIN only):
curl -X DELETE https://app.headlessops.ai/api/workspaces/ws_abc123/labels/client-acme \
-H "Authorization: Bearer iter_YOUR_KEY"Deleting a label removes it from the registry and from all resources. Grants for that label are also removed.
API Keys Inherit Label Grants
Before IAM v1, API keys had full workspace access. Now they inherit the label grants of the user who created them.
If Alice has read access to client-acme and creates an API key, that API key can only see resources tagged client-acme. It cannot access resources tagged team-internal even if those exist in the same workspace.
This means you can safely give a client their own API key — it will only surface resources you have labeled for them.
ADMINs and OWNERs still create keys with full access. API key scope is limited only for non-admin members.
Credential Access for Developers
When an integration uses credentials that a developer does not have a label grant for, the following behavior applies:
- The developer can view the integration (if they have a label grant for the integration itself) but they cannot run, deploy, or edit it.
- Attempting to run the integration shows a popup:
"You do not have access to credentials: X, Y, Z. Ask your workspace admin to share those credentials with you or set up this integration."
- Attempting to save or deploy the integration shows a similar error popup instead of proceeding.
- The developer is not redirected away from the page — the restriction is surfaced as an inline dialog.
In short: An integration is runnable/editable by a developer only if they hold a label grant for both the integration and all credentials it uses.
Admin-Level Integrations
When an ADMIN or OWNER runs or deploys an integration authored by a developer, the integration is elevated to admin-level. This means:
- The integration runs with the admin's full credential access, so no "credential does not exist" errors appear in logs.
- The integration is tagged internally as
adminLevel: true. - After elevation, the original developer author can still view the integration but can no longer edit or deploy it (even if they originally created it).
- Only ADMINs and OWNERs can edit and redeploy an admin-level integration.
This mechanism allows admins to take over sensitive integrations from developers without blocking visibility.
Common Setup Patterns
Pattern 1 — Client Isolation
You manage automations for multiple clients in one workspace.
Label: client-acme
→ Integration: acme-crm-sync
→ Credential: acme-salesforce-key
→ KnowledgeDoc: acme-schema.md
Label: client-bravo
→ Integration: bravo-reporting
→ Credential: bravo-db-connectionGrant each client's team member read access to their own label. They only see their resources.
Pattern 2 — Team Segmentation
You have multiple internal teams.
Label: team-data → Data engineering integrations
Label: team-ops → DevOps automations
Label: team-product → Product analyticsGrant each developer write access to their team's label so they can manage labeling themselves.
Pattern 3 — Environment Separation
Label: production → Live integrations (read grants for most members)
Label: staging → Test integrations (write grants for developers)This prevents developers from accidentally editing production integrations when browsing the workspace.
Quick Reference
| Task | Who Can Do It | How |
|---|---|---|
| Create a label | Any member (implicitly, by assigning it) | PATCH /:resource/labels |
| Grant label access | ADMIN / OWNER | POST /members/:mid/label-grants |
| Remove label access | ADMIN / OWNER | DELETE /members/:mid/label-grants/:id |
| Assign label to resource | ADMIN/OWNER, or write grant holder | PATCH /:resource/labels |
| Remove label from resource | ADMIN/OWNER, or write grant holder | PATCH /:resource/labels |
| List all labels in workspace | Any member | GET /workspaces/:wid/labels |
| Edit label description | ADMIN / OWNER | PUT /workspaces/:wid/labels/:name |
| Delete label from registry | ADMIN / OWNER | DELETE /workspaces/:wid/labels/:name |
Relationship to Roles
Label-based access works on top of the existing role system. Roles still control what actions a member can perform — labels control which resources they can see.
| OWNER / ADMIN | Sees everything, always. Labels do not restrict them. |
|---|---|
| DEVELOPER / MEMBER | Sees only resources that have a label they hold a grant for. |
| VIEWER | Same label scoping applies, but they still cannot trigger runs or edit. |
For the full role reference, see Users & RBAC.
Next Steps
- Users & RBAC — understand roles and how they interact with label grants
- Workspace Management — manage API keys (now label-scoped for non-admins)
- MCP Overview — how label access applies when using AI agents via MCP
Users & RBAC
Role-based access control, user invites, two-factor authentication, and how roles interact with label-based permissions
Failure Alert Notifications
HeadlessOps sends personalised email alerts when an integration run fails. Configure recipients, webhook URLs, and unsubscribe behaviour via the UI or MCP — with HMAC-signed stateless unsubscribe links built in.