# Managing access

> Learn how an owner approves an agent grant, sets monthly spend caps for purchases, receives owner emails, and reviews or revokes agent access from the console.

Source: https://docs.customdomain.ai/docs/agents/managing-access

Everything an agent can do is gated by a **grant** a human owner approved. This
page covers the owner side: consenting, controlling spend, and revoking. The
console's **Agents** page, where you review and revoke grants, is off by default
for each workspace and switches on after your first approval; see
[Reviewing and revoking](#reviewing-and-revoking).

## Approving a grant

When an agent starts the [authorization flow](/docs/agents/oauth-flow), the
control plane parks the request and sends the owner to the console consent page
(`/agent/consent`). It works whether or not the Agents page is on. If you are
signed out, you are bounced to sign in first: a grant can only be approved by a
real, signed in owner.

The page shows which agent is asking and the scopes it requested. An agent
chooses its own name, so the page leads with what the agent cannot choose
freely: **where its access would go**, the host your approval sends the browser
(and the access) back to. That host carries one of four labels:

* **Verified**: a known assistant's own address, such as `claude.ai`,
  `chatgpt.com` or `app.devin.ai`.
* **Local tool**: a program on your own computer (`localhost`). Approve only if
  you started that program yourself just now.
* **Unverified**: any other address. You can still approve, after confirming
  that you recognize the host and started the connection yourself. The control
  plane refuses the approval without that confirmation.
* **Blocked**: the agent's name imitates a brand (Claude, ChatGPT, OpenAI,
  Anthropic, Devin, CustomDomain™) that its host does not belong to. It can only
  be denied.

The page also shows when the agent registered, or which site publishes its
details. You approve a subset of the scopes, choose whether access is
**persistent** (the default) or expiring, and, if `domains:purchase` is
requested, set a monthly spend cap and save a card. On approval the browser is
handed back to the agent to finish the token exchange. **Deny** cancels the
request so it cannot be approved later; a verified or local agent is told it was
denied, and an unverified or blocked one is not sent anywhere.

The page also says **where it acts**: your workspace, by name, and the
application the agent will work in. With one live application it is named; with
several you choose one, and the application selected in the console is chosen to
start with. Test mode applications are not offered, because they have no real
domains, and a workspace with no live application cannot approve an agent. The
grant is bound to the application you approve, so the agent can act only on that
application's domains.

> Consent is recorded by the console **server side** with your workspace API key,
> and the approving member must belong to your workspace. A member's own key
> records only that member as the approver. A browser or embed token can never
> approve an agent, so a client can never approve itself.

## Spend caps and purchases

Purchase access (`domains:purchase`) is **fail closed**. Granting it requires,
all three:

1. the `domains:purchase` scope is approved,
2. an explicit **monthly spend cap**, and
3. a **saved payment method** on file (add one from the consent flow's billing
   step, which opens a Stripe card setup with no charge).

At runtime every agent purchase is checked against the grant's cap for the
current month **before** any money moves. A purchase that would exceed the cap is
refused, and you are emailed that the cap was reached. A failed registration never
consumes the cap.

Purchases through MCP are off on the hosted service, so approving this scope does
not let an agent spend there.

## Owner emails

You are kept in the loop automatically:

* **Connected**: when a new grant is approved, with exactly what it can do.
* **Acted**: when the agent takes an action (for example, connects a domain).
* **Purchased**: immediately when it spends money (an urgent alert).
* **Revoked**: when access ends.
* **Revoked for your safety**: when CustomDomain™ ends an agent's access on its
  own because one of its credentials was used twice, which can mean it was
  copied. Reconnect the agent if you still want it.

Every email links to your agent management page so you can review or revoke in
one click.

## Reviewing and revoking

The **Agents** page (`/app/settings/agents`, in the sidebar under **More**) lists
every active grant: the agent, the application it acts in, when it was last used,
and its scopes. A grant that can spend also shows this month's spend against its cap,
and an expiring grant shows its end date. **Revoke** ends it immediately: the
control plane refuses the agent's next tool call (the MCP answers it with HTTP
`401`), and its refresh token is killed.

The page is off by default for each workspace. It switches on by itself when you
approve an agent, so you never approve a grant you cannot find. You can
also switch it on or off under **Settings → Features** (admins and owners). The
welcome leads to the setup for your agent (**My AI writes the code** on a product's
path, or **Let an AI agent connect domains** on the last screen for clients or a
domain of your own); its grant is listed here once it signs in and you approve it.
Switching the page off hides it; it does not revoke anything.

The same operations are available over the API with your workspace API key:

```bash
# List grants
curl https://api.customdomain.ai/v1/agent/grants \
  -H "Authorization: Bearer cd_live_…"

# Revoke a grant
curl -X DELETE https://api.customdomain.ai/v1/agent/grants/grt_… \
  -H "Authorization: Bearer cd_live_…"
```

These endpoints require the workspace API key (not a widget or browser token),
the same credential that records consent.
