---
title: "Grant (or update) an agent's access to an integration connection"
method: POST
path: "/agents/{agentId}/integration-grants"
tags: ["Integrations"]
---

# Grant (or update) an agent's access to an integration connection

`POST /agents/{agentId}/integration-grants`

## Request

- Base URL: `https://api.atako.ai`
- URL: `https://api.atako.ai/agents/{agentId}/integration-grants`
- Auth: HTTP bearer

Upsert on (agentId, connectionId). Allowed for the agent's owner or an admin of the owner's company. A PERSONAL connection can only be granted by its creator, to an agent they own (403 personal_grant_owner_only).

## Path parameters

- `agentId` string, required

## Request body

- object
  - `connectionId` string, uuid
  - `allowedTools` string[]: Filtered server-side to valid connector actions.
  - `scope` 'read' | 'write' | 'read_write'
  - `expiresAt` string, date-time, nullable
  - `constraints` object, nullable

## Response `201`

- IntegrationGrant
  - `id` string, uuid, required
  - `agentId` string, uuid
  - `connectionId` string, uuid, required
  - `allowedTools` string[]
  - `scope` 'read' | 'write' | 'read_write', required
  - `constraints` object, nullable
  - `grantedBy` string, uuid
  - `expiresAt` string, date-time, nullable
  - `createdAt` string, date-time, required
  - `connection` object: Only present on the list endpoint (joined).
    - `providerKey` string
    - `displayName` string, nullable: null on a masked row.
    - `status` 'active' | 'error' | 'revoked'
    - `visibility` 'company' | 'personal'
  - `masked` boolean: List endpoint only: true for another user's PERSONAL connection (an admin viewing a colleague's agent) — no connection name, only `ownerName`. Revocable, not editable.
  - `ownerName` string, nullable: Masked rows only: the personal connection owner's first name.
  - `isDefault` boolean: Present (true) ONLY on a SYNTHETIC row the list endpoint fabricates for a companyWide+defaultGranted connector (e.g. 'projects') when this agent has no explicit integration_grants row yet — it already has full access by default; this row lets the UI show that instead of "no access". `id`/`connectionId` both equal the connection's own id on a synthetic row (no real grant row exists) — DELETE on that id persists an opt-out (a real row with allowedTools:[]) instead of a no-op. Absent (never false) on a real row.

## Other responses

- `400`: connectionId required / connection_not_found / unknown_provider / no_valid_tools
- `401`: Missing, malformed, or invalid bearer token / API key, or revoked session (SESSION_REVOKED).
- `403`: engine_capability_denied / personal_grant_owner_only
- `404`: not_found — no such agent, or the caller neither owns it nor administers its company.

---

[API](https://skmtc.dev/atako/apis/atako-api.md) · [All operations](https://skmtc.dev/atako/apis/atako-api/llms.txt) · [OpenAPI document](https://skmtc.dev/atako/apis/atako-api/revisions/aa555c56fbd7?raw)
