HeadlessOps
Platform

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:

  1. Assign a label to a resource (e.g. client-acme or team-data)
  2. Grant a team member access to that label
  3. 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:

GrantView resourceRun integrationEdit code & configAssign/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 → Deny

Labels Across Resource Types

You can apply labels to three types of resources:

ResourceSupports 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

  1. Go to Workspace Settings → Members
  2. Click on the member's name
  3. Under Label Access, click Add Grant
  4. Type the label name and choose read or write
  5. Optionally set an expiry date/time for a temporary grant (see below)
  6. 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 expiresAt unset (or null) for a permanent grant — the default behavior.
  • Set expiresAt to 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 write grant 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-connection

Grant 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 analytics

Grant 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

TaskWho Can Do ItHow
Create a labelAny member (implicitly, by assigning it)PATCH /:resource/labels
Grant label accessADMIN / OWNERPOST /members/:mid/label-grants
Remove label accessADMIN / OWNERDELETE /members/:mid/label-grants/:id
Assign label to resourceADMIN/OWNER, or write grant holderPATCH /:resource/labels
Remove label from resourceADMIN/OWNER, or write grant holderPATCH /:resource/labels
List all labels in workspaceAny memberGET /workspaces/:wid/labels
Edit label descriptionADMIN / OWNERPUT /workspaces/:wid/labels/:name
Delete label from registryADMIN / OWNERDELETE /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 / ADMINSees everything, always. Labels do not restrict them.
DEVELOPER / MEMBERSees only resources that have a label they hold a grant for.
VIEWERSame 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