Usage Policy API

Read and write a workspace's or organization's usage policy — the governance layer that limits which outside apps, knowledge, MCP servers, agents, and flows members may use.

→ Usage policy (product guide) — reach, allowed/blocked lists, and blocked attempts in the web app
→ Workspaces API — members, roles, and workspace context

Requires API key scopes teams:read (read policy, denials, effective access) or teams:write (replace or clear a layer). Within a workspace, the server also checks member capabilities:

CapabilityWho typically has itUsed for
view_policyEvery member of the workspace, and members of any workspace in its organizationGET workspace/org rules and GET effective access
manage_policyWorkspace owner (standalone team); org admins on the org workspace and on every member workspacePUT / DELETE rules, denials feeds, POST effective access (draft preview)

Org routes use {id} = the organization workspace team id (type: "org"). Member workspace routes use that workspace's team id.


Model

A usage policy is a PolicyLayerDTO: the same shape as other governance layers in the rules API (for example an agent's rules at /agents/{id}/rules), but scoped to usage kinds only.

FieldDescription
subject_typeteam, org, or user (a member policy written by a workspace admin)
subject_idTeam or org id
labelDisplay name for the layer
governanceAlways true for usage policy
editabletrue when the caller may change this layer (see below)
reachMap of usage kind → reach (public, org, team, or private). A missing kind means public (no restriction for that category).
reach_enforcedUsage kinds whose reach is enforced on this governance layer (see below). Each kind must also appear in reach with a non-empty value.
rulesGovernance rules for this layer. Usage rules use effect allow or deny on App, Agent, Knowledge, Mcp, or Flow. Agent-action rules use allow, ask, or deny on RemoteExec, Workspace, WebFetch, Harness, or Tool (see below). Each rule has kind, specifier, optional selector (machine or tag:…), and label.
rule_kindsWhen editable, lists which rule kinds may be added on this layer (usage kinds and/or agent-action kinds, with selector: true when a machine may be named)
lintWhen editable, problems with the layer's rules: rules that cancel each other, can never match, allow too much, or never take effect

Usage kinds (also used in reach keys and rule kind):

KindCategory
AppApps
KnowledgeKnowledge and skills
McpMCP connectors
AgentAgents
FlowFlows

Reach values match the product guide: public (everything visible), org (same organization), team / private (this workspace only).

Enforced reach (reach_enforced) is a governance-only floor for a category. When an org or workspace admin enforces apps at organization, for example, every lower admin layer (member workspace policy, member policy) may narrow that reach (stricter reach, deny rules) but cannot loosen it — not with a wider reach and not with an allow rule, including rules marked enforced. The layer that set the enforced reach keeps its own allow rules as exceptions to that floor. Only kinds with a reach set in reach may appear in reach_enforced; the server returns 400 otherwise. Narrow-only layers (chat, agent, user personal rules) cannot enforce reach.

Each rule has kind, effect, enforcement, specifier, and label. Usage rules accept allow or deny only. Agent-action rules also accept ask (prompt before proceeding). At write time, usage rules may send a human ref (publisher/app-name, publisher/*, an MCP slug, and so on) or reuse a specifier from a prior response or denial row. Agent-action rules send specifier directly (for example git push:*, ~/secrets/**, domain:github.com, Bash(git status:*)).

Agent-action rule kinds

These rules govern what agents may run on machines and call over the network. In the web app they appear under usage policy → agents → what agents can do. They share the governance layer with usage reach and exceptions but are added or removed one at a time with POST / DELETE (or on member policies, the member routes below).

kindspecifier examplesselector (optional)
RemoteExecgit push, git push:*Machine id or tag:prod
Workspace~/secrets, ~/proj/**Machine id or tag:…
WebFetchdomain:github.com—
HarnessEdit, Bash(git status:*)Machine id or tag:…
Toolweb_search—

enforcement controls how the rule participates in decisions. Omit it on create or replace; the server stores default.

ValueMeaning
defaultThe rule decides in its layer. A more specific admin layer with a matching rule can override it.
enforcedGovernance only (org or workspace policy). Final for admin layers: checked before other governance rules and cannot be overridden by a lower admin layer.
evaluateThe rule never decides. When it would have changed an outcome, the blocked attempts feed records what it would have done — useful for trying a rule before turning it on.
disabledKept in the layer but ignored.

Only manage_policy callers may set enforced on org or workspace rules. Chat, agent, and remote rules always use default.

For usage kinds, after resolution specifier is always a stable id:

TargetStored specifier
One resourceThat resource's id (for example app_123)
Every resource from a publisherpublisher:<team id>

label is the display string for the rule — the same ref you wrote (for example bytedance/seedance or bytedance/*). Responses and denials echo specifier and label so clients never construct a specifier. deny rules correspond to blocked entries in settings; allow rules correspond to allowed exceptions.

How layers combine

Governance layers (organization, workspace, member policy) are checked most specific first. The most specific layer that speaks to a call decides it: one with a rule that matches the call, or, for a usage kind, one that sets a reach for that kind. A layer with nothing to say passes the call up. A more specific governance layer may therefore be looser than the one above it, except where the higher layer enforces a reach (reach_enforced) or a rule (enforcement: "enforced"); those are final for every lower admin layer.

When a workspace inside an organization has no layer of its own, GET /teams/{id}/rules returns the org's layer with editable: false; change it with /orgs/{id}/rules. In an organization, manage_policy on a member workspace belongs to the org admins, so only they can write that workspace's own layer. The web app edits org-governed workspaces only through the organization's policy page.


Workspace policy

Get layer

GET /teams/{teamId}/rules

Returns the governance layer in force for the workspace: its own layer, or the org's layer when it has none.

bash
1curl "https://api.inference.sh/teams/team_xyz/rules" \2  -H "Authorization: Bearer inf_your_key"

Example response:

json
1{2  "subject_type": "team",3  "subject_id": "team_xyz",4  "label": "Acme",5  "governance": true,6  "editable": true,7  "reach": {8    "App": "org",9    "Mcp": "public"10  },11  "reach_enforced": ["App"],12  "rules": [13    {14      "id": "rule_abc",15      "effect": "deny",16      "enforcement": "default",17      "kind": "App",18      "specifier": "app_123",19      "label": "competitor/scraper",20      "created_at": "2026-09-01T12:00:00Z",21      "created_by": "usr_owner"22    }23  ],24  "rule_kinds": [25    { "kind": "App", "selector": false },26    { "kind": "Agent", "selector": false }27  ]28}

Replace layer

PUT /teams/{teamId}/rules

Replaces the workspace's reach and usage-kind rules in one request. Rules of other kinds on the same subject are unchanged.

Request body (PolicyLayerSetRequest):

json
1{2  "reach": {3    "App": "org",4    "Agent": "team",5    "Knowledge": "public",6    "Mcp": "public",7    "Flow": "public"8  },9  "reach_enforced": ["App"],10  "rules": [11    {12      "effect": "allow",13      "kind": "App",14      "ref": "partner/vendor-tool",15      "label": "partner/vendor-tool"16    },17    {18      "effect": "deny",19      "enforcement": "default",20      "kind": "Mcp",21      "ref": "untrusted-mcp"22    }23  ]24}

Requires teams:write and manage_policy.

Clear layer

DELETE /teams/{teamId}/rules

Removes the workspace's own governance layer so defaults apply (or the org layer when inside an org). Requires teams:write and manage_policy.

Response: { "status": "cleared" }

Update one rule

PUT /teams/{teamId}/rules/{ruleId}

Changes only enforcement on an existing usage rule (PolicyRuleUpdateRequest). The rule's kind, effect, and target stay the same; to change those, delete the rule and add another with PUT /teams/{id}/rules or POST on a narrow-only layer.

json
1{ "enforcement": "evaluate" }

Requires teams:write and manage_policy.

DELETE /teams/{teamId}/rules/{ruleId} removes a single rule without replacing the whole layer.

Add or remove agent-action rules

POST /teams/{teamId}/rules — body is a PolicyRuleCreateRequest with an agent-action kind (RemoteExec, Workspace, WebFetch, Harness, or Tool), effect (allow, ask, or deny), specifier, and optional selector / enforcement. Other rules on the layer are unchanged.

DELETE /teams/{teamId}/rules/{ruleId} removes one agent-action or usage rule.

Requires teams:write and manage_policy.


Organization policy

Get layer

GET /orgs/{orgTeamId}/rules

Same response shape as the workspace route. {orgTeamId} must be the organization workspace's team id.

Replace layer

PUT /orgs/{orgTeamId}/rules

Same body as PUT /teams/{id}/rules. Governs every workspace in the organization. A member workspace's own layer, written by org admins, may loosen it except where it enforces a reach or a rule.

Clear layer

DELETE /orgs/{orgTeamId}/rules

Clears the org-wide layer.

Update one rule

PUT /orgs/{orgTeamId}/rules/{ruleId} — same body and semantics as the workspace route. DELETE /orgs/{orgTeamId}/rules/{ruleId} removes one rule.

Add or remove agent-action rules

POST /orgs/{orgTeamId}/rules and DELETE /orgs/{orgTeamId}/rules/{ruleId} — same bodies and semantics as the workspace POST / DELETE routes above.


Member policy

A workspace admin with manage_policy can attach a member policy to one user in that workspace. It is governance scoped to the workspace that wrote it (or to every workspace in the organization when written from the organization workspace). For that member, it decides the usage calls its reach and usage-kind rules match; other members follow the workspace or org layer only.

Until a member policy exists, GET /teams/{teamId}/members/{userId}/rules returns the workspace's layer with subject_type: "team" and editable: false — a template to start from. After PUT, responses use subject_type: "user", governance: true, and editable: true.

Member policies are stored separately from the member's own narrow-only rules (GET /me/rules). Both can be attached at once: the admin layer governs what the member may use in this workspace; personal rules only narrow tool and machine access and apply everywhere that person works.

When someone leaves a workspace (or the organization), member policies that workspace or org wrote for them are removed so they do not apply again on a later re-invite.

Get layer

GET /teams/{teamId}/members/{userId}/rules

Requires teams:read and manage_policy. {userId} must be a member of {teamId}.

Replace usage layer

PUT /teams/{teamId}/members/{userId}/rules

Same body as PUT /teams/{id}/rules (reach plus usage-kind rules). Requires teams:write and manage_policy.

Clear layer

DELETE /teams/{teamId}/members/{userId}/rules

Removes the member policy; the user follows the workspace (or org) layer again.

Machine rules on a member

Usage kinds must be written with PUT as a whole. To govern what that member's agents may run on machines (RemoteExec, Workspace, WebFetch, Harness, Tool), add or remove rules one at a time:

  • POST /teams/{teamId}/members/{userId}/rules
  • DELETE /teams/{teamId}/members/{userId}/rules/{ruleId}
  • PUT /teams/{teamId}/members/{userId}/rules/{ruleId} — change enforcement only

Same rule shapes as chat and agent permission rules (RemoteExec, Workspace, WebFetch, Harness, Tool).


Test a call

POST /teams/{teamId}/rules/explain
POST /orgs/{orgTeamId}/rules/explain

Tests one call against the governance layers in force for the workspace, without making it. Requires teams:read and view_policy.

Request body (ChatRuleExplainRequest):

FieldDescription
kindRemoteExec, Workspace, Harness, Tool, or a usage kind (App, Agent, Knowledge, Mcp, Flow)
targetThe call: a command, a path, a harness tool call (Bash(git status)), a tool name, or a resource id for a usage kind
owner_team_idOptional. The team that owns a usage kind's resource, so publisher rules, org reach and the workspace's own resources apply
remoteOptional. The remote the call runs on, so rules with a selector apply
cwdOptional. Working directory for relative paths

Response (ChatRuleExplainDTO): effect, the deciding rung and rule (null when no single rule decided), a one-sentence reason, and would_have when a rule in evaluate mode would have decided otherwise.


Blocked attempts

Aggregated refusals for the policy editor's blocked attempts feed.

GET /teams/{teamId}/rules/denials
GET /orgs/{orgTeamId}/rules/denials

Requires teams:read and manage_policy.

Each row (PolicyDenialDTO) includes kind, specifier, label, count, last_at, and optionally owner_team_id. Use the same kind and specifier (or ref at write time) when adding an allow rule from the feed.


Effective access

Paginated list of resources for one usage kind, each with allowed or blocked and a reason — the same evaluation the server uses on real usage. Powers search in the allowed/blocked pickers and reach previews.

GET /teams/{teamId}/rules/access
POST /teams/{teamId}/rules/access

Requires teams:read and view_policy for GET. POST (draft preview) additionally requires manage_policy on the workspace. Only defined for workspaces (not org routes).

Query parameters (GET):

ParameterDescription
kindRequired. Usage kind: App, Agent, Knowledge, Mcp, or Flow
querySearch names and publishers
outcomeallowed or blocked to filter; omit for both
cursor, limitPagination

POST body (UsageAccessRequest): same fields as query parameters, plus optional draft:

json
1{2  "kind": "App",3  "query": "invoice",4  "outcome": "blocked",5  "limit": 20,6  "draft": {7    "reach": { "App": "org" },8    "rules": []9  }10}

When draft is set, the server substitutes that unsaved reach and rule set for the layer you are editing inside the full policy ladder (organization, workspace, member, and personal rungs that already apply). Higher layers — including enforced org reach — still decide outcomes the draft cannot loosen. This matches enforcement on real usage, not an isolated preview of the draft alone.

Response (UsageAccessPageDTO):

json
1{2  "items": [3    {4      "resource_id": "app_456",5      "specifier": "app_456",6      "publisher_specifier": "team_partner",7      "ref": "partner/invoice-ocr",8      "owner_team_id": "team_partner",9      "publisher": "partner",10      "source": "organization",11      "source_name": "Acme Org",12      "outcome": "blocked",13      "reason": "outside_reach",14      "decided_by": {15        "subject_type": "org",16        "subject_id": "team_org_acme",17        "label": "Acme",18        "governance": true19      },20      "enforced": true21    }22  ],23  "next_cursor": "..."24}
FieldMeaning
decided_byWhich policy layer's reach or rule decided (PolicyRungDTO). Omitted for this workspace's own resources and for ungoverned defaults inside reach.
enforcedtrue when an enforced reach or rule on that layer decided; the draft being edited cannot change this outcome.

Clients that add allow or block shortcuts from a row should treat enforced: true with decided_by pointing at a layer other than the one being edited as locked: the outcome cannot be widened from that editor (for example the web app appends by Acme (enforced) to the reason line and hides allow). Saving an allow rule for that resource on the lower layer is rejected the same way.

reasonMeaning
own_workspaceOwned by this workspace
defaultInside reach, not blocked
allow_ruleNamed by an allow rule
block_ruleNamed by a deny rule
outside_reachOutside reach with no allow rule
unresolvedPolicy could not be loaded; only own workspace resources are allowed

Each item includes specifier and publisher_specifier for building rules without guessing ids.


Errors

When usage is refused at runtime, API responses may include error code blocked_by_usage_policy. Denials are also written to the audit log.


Migration from /usage-policy

The former /teams/{id}/usage-policy and /orgs/{id}/usage-policy routes and UsagePolicy* request/response types are removed. Use the /rules paths and PolicyLayerDTO / PolicyLayerSetRequest above instead. Storage and enforcement behavior are unchanged; only the HTTP surface and DTO names moved into the shared rules API.

we use cookies

we use cookies to ensure you get the best experience on our website. for more information on how we use cookies, please see our cookie policy.

by clicking "accept", you agree to our use of cookies.
learn more.