Skip to content

Guide · Control

How to give an AI agent access to your business systems: permissions, approvals, caps and a record

Updated Published By the actionlake team

To give an AI agent access to business systems without losing control, put seven controls between the agent and the systems: keep vendor credentials out of the agent's reach, give each agent its own scoped key, start read-only, cap what each key can spend, make chosen actions wait for a named person, dry-run anything new, and record every action with the agent's reason. Each control below has a one-line test you can apply to any setup, and the exact setting in actionlake, an MCP gateway that applies all seven on every call.

The risks you are controlling

Before the controls, name the failure modes. They are ordinary, and they are why "just give it an API key" goes wrong.

RiskWhat it looks like
Leaked credentialsA vendor token pasted into a prompt, a config file or a shared laptop
Too much scopeAn agent built to read invoices can also void them, because the token can
Runaway callsA retry loop burns a vendor's hourly API limit, or your budget, before lunch
Unwanted writesA plausible but wrong update to a customer record, a ticket or a user
Duplicate writesA timeout, a retry, and the same invoice is created twice
No recordSomething changed, and nobody can say which agent did it, or why

1. Keep credentials out of the agent's reach

Test: can the model, the prompt or the agent's machine ever read the vendor's token?

The agent should hold a credential you issued and can revoke, never the vendor's own. In actionlake, vendor credentials live in a credential vault: sealed with AES-256-GCM under a per-tenant data key, opened in memory for one outbound request, never logged and never returned by any endpoint. The agent holds an actionlake key. Connect a system once:

{
  "op": "connections.create",
  "service": "halopsa",
  "secrets": { "client_id": "…", "client_secret": "…" },
  "setup_data": { "tenant_host": "https://yourcompany.halopsa.com" }
}

Ask connections.requirements first; it lists exactly which fields each service needs.

2. One key per agent, scoped to its job

Test: if this agent goes wrong, which systems and actions can it reach?

Give every agent, or every person's agent, its own key. Scope it with allowed_actions:

EntryGrants
xero.invoices.listOne action
autotask.*Every action in one service
read:*Every read in every connected service
hubspot_crm.read:*Every read in one service
service.ticket.createOne canonical action, in whichever ticket system is connected

A key can mint child keys, but only with a subset of what it holds and a share of its cap. Revoke a key and every key it minted stops too. A read that reveals a stored secret, such as a password in a documentation system, is not covered by read:*; it needs a grant that names it. See AI agent permissions.

3. Start read-only

Test: what is the worst thing this agent can do today?

Reads answer most of the questions people ask first: what is overdue, what is open, who is this customer. Start every new agent on read:* or <service>.read:*, watch what it does for a week, then add named write actions one at a time.

4. Cap every key

Test: if the agent loops for an hour, what stops it?

A cap counts upstream calls, the requests actually sent to a vendor. In actionlake, cap_calls is reserved before the call and settled after it, so the call that would cross the cap is refused before it is sent. Caps cascade: a child key's calls count against every key above it, so a team's parent key bounds every agent under it. On the Free plan the tenant itself stops at its allowance; there is no overage to surprise you. See agent spending cap.

5. Put a person in front of the actions that matter

Test: which actions should never run on the agent's word alone?

There are two settings, and they work together.

confirm_policy, per key:

ValueBehaviour
agentThe agent may confirm its own destructive actions with confirm: true
human_for_writesEvery write needs an explicit confirm: true; nothing changes on a bare call
humanDestructive actions wait for a person's approval; the agent cannot confirm them itself. Writes that create or change a billing record need confirm: true

approval_rules, per key: any action matching a pattern waits for a named person, whatever its effect.

{
  "name": "finance-agent",
  "allowed_actions": ["xero.read:*", "xero.invoices.create", "xero.payments.create"],
  "cap_calls": 5000,
  "confirm_policy": "human",
  "approver": "[email protected]",
  "approval_rules": [
    { "match": "xero.payments.create", "approver": "[email protected]" },
    { "match": "xero.write:*", "approver": null }
  ]
}

A matched call does not fail; it waits. The approver gets an email with a signed link, or decides in the console, and the run continues when they approve. A rule with no approver falls to the key's approver, then to the tenant's. See human-in-the-loop approval.

6. Dry-run anything new

Test: can you see what a call will do, and cost, before it happens?

check takes the same payload as do or ask. It validates the input against the action's schema, checks the key's permissions and the connection, estimates the calls and the cost, and says what would need a confirmation or an approval. It is free and sends nothing to the vendor. Agents call it before a new kind of action; people can ask for it ("check this first"). See dry run.

7. Record every action, with the reason

Test: six months from now, can you show who did what, where, at what cost, and why?

Every actionlake run requires an intent: one sentence from the agent saying why it acted. Every run is a row in a ledger with the key, the action, the connection, hashes of the input and output, the outcome and the cost. Rows are chained with SHA-256, so altering a past row breaks every hash after it, and the chain head is sealed to storage daily. The record is permanent. The intent text is kept for 90 days. See AI agent audit logs.

Duplicate writes: not retried, not cached

Writes are never cached and never retried automatically. A write that timed out is reported as such; the agent can look before it tries again. Reads are cached per connection, and a write invalidates the reads it affects.

The seven controls on one page

Controlactionlake settingCost
Credentials out of reachConnection in the vaultFree
Scoped key per agentallowed_actionsFree
Read-only firstread:* or <service>.read:*Free
Capcap_callsFree
Approvalconfirm_policy, approval_rules, approverFree
Dry runcheckFree
Record with reasonintent on every run; the ledgerFree

You pay only for upstream calls that were sent. The Free plan includes 100,000 a month. See pricing.

What is still your job

A gateway enforces the rules you write; it does not choose them. You still decide which actions each agent needs, who approves what, and what the vendor-side user may do. Keep the vendor API user at least privilege too: actionlake narrows what an agent may run, and cannot grant more than the vendor account allows. actionlake holds no SOC 2 or ISO 27001 certification today; the trust page lists what is in place and what is not.

Frequently asked questions

Is it safe to give an AI agent write access?

Safety is the result of controls, not a property of the agent. With a scoped key, a cap, approval rules on the writes that matter and a full record, an agent can write within limits you chose and can show what it did. Start read-only and add writes one action at a time.

Can an agent raise its own permissions?

No. A key can only mint keys with a subset of its own grants and a share of its own cap. Administering connections, approvals and billing needs separate grants that a bare * does not include. Keys are never minted through an OAuth token.

What happens when the cap is reached?

The next call is refused before it reaches the vendor, with a clear error. Nothing is sent and nothing is billed. Raise the cap, or wait for the next period.

Who can approve an action?

The approver named on the matching rule, then the key's approver, then the tenant's default. A decision only counts from that person, the tenant's delegate, or a key outside the waiting run's own key chain, so an agent cannot approve itself.

Try it on your own systems.

100,000 free calls a month. No card. Hard caps on every key.