Documentation
DocsAPI reference

Agents

Agents are the AI systems that ask for approval. Each agent has instances, and each instance holds a credential it uses to call the API.

Updated Sep 22, 2026

Tokens are returned once, when issued, and are never shown again.

Register an instance to get a credential directly, or create a provisioner token so each replica can create its own instance through the Agent Approval Protocol (AAP).

List agents

GET/api/v1/agentsSession or API keyRequires agent.read

Returns the organization's agents. Each entry carries the agent's instance counts, when it was last seen, and how many requests it has made. Active agents come first, then disabled ones, then archived ones, each group sorted by name. Archived agents are left out unless status says otherwise.

An agent is live when one of its instances holds a credential that is neither expired nor revoked. last_seen_at is the newest authenticated call from any of its instances. Agents only call in when they have something to approve, so a quiet agent is not a broken one.

Request

Parameters

ParameterTypeDescription
statusquery · enum

Which agents to return. live (the default) returns active and disabled agents, archived returns only archived ones, and all returns every agent.

One of live, archived, all
limitquery · integer

How many agents to return. Defaults to 50.

Response

Response codes

StatusBodyDescription
200object

The agents

400ErrorResponse

status is not live, archived, or all

403ErrorResponse

You cannot read agents

Response body200

agentsarray<Agent>required

Example

GET /api/v1/agents
curl -X GET "$WITHHUMAN_URL/api/v1/agents" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "agents": [
    {
      "slug": "support-bot",
      "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "name": "Support bot",
      "status": "active",
      "created_at": "2026-09-08T12:02:11Z",
      "updated_at": "2026-09-08T12:02:11Z",
      "archived_at": "2026-09-08T12:02:11Z",
      "instance_count": 0,
      "live_instance_count": 0,
      "last_seen_at": "2026-09-08T12:02:11Z",
      "recent_request_count": 0,
      "pending_request_count": 0,
      "request_trend": [
        0
      ]
    }
  ]
}

Create an agent

POST/api/v1/agentsSession or API keyRequires agent.write

Creates an agent. An agent is a stable identity for one AI system, such as a support bot or a deploy assistant. Its slug is the identity: chosen here, never changed, never reused. Every agent owns one approval pipeline, created empty with the agent.

Creating an agent does not issue a credential. Register an instance, or create a provisioner token, to let it call the API.

Request

Request body

slugstringrequired

The agent's identity. Lowercase letters, digits, dots, underscores and hyphens, up to 63 characters. It cannot change and is never reused, so a slug an archived agent holds is refused.

namestringrequired

A display name. Reviewers see it on every request the agent makes. It can be changed later and must be unique among the organization's live agents.

Response

Response codes

StatusBodyDescription
201Agent

The new agent

403ErrorResponse

You cannot create agents

409ErrorResponse

The slug is taken by a live or archived agent (agent_slug_taken), or a live agent already has the name (agent_name_taken)

429

The organization is at its agent limit

Response body201

slugstringrequired

The agent's identity, chosen once at creation. It never changes and is never reused, not even after the agent is archived.

organization_iduuidrequired

The membership or organization-key actor that created the agent.

namestringrequired

The display name. Reviewers see it on every request. Editable, and unique among the organization's live agents.

statusenumrequired

A disabled agent's instances cannot authenticate until it is enabled again. An archived agent is retired: nothing of it authenticates, nothing can be enrolled under it, and its status cannot change until it is restored.

One of active, disabled, archived

created_atdate-timerequired
updated_atdate-timerequired
archived_atdate-time

When the agent was archived. Present exactly when status is archived.

Example

POST /api/v1/agents
curl -X POST "$WITHHUMAN_URL/api/v1/agents" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "slug": "support-bot",
  "name": "Support bot"
}'
201 response
{
  "slug": "support-bot",
  "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "name": "Support bot",
  "status": "active",
  "created_at": "2026-09-08T12:02:11Z",
  "updated_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z"
}

Retrieve an agent

GET/api/v1/agents/{slug}Session or API keyRequires agent.read

Returns one agent with a page of instances, each instance's credentials, and its provisioner tokens. Secrets are never included. Instances are sorted by last seen, then creation time and id, newest first. Counts and connection state cover all instances, independent of the page and filters.

Request

Parameters

ParameterTypeDescription
slugrequiredpath · string

The agent's slug: the identity chosen when it was created, never changed and never reused.

instance_limitquery · integer

Number of instances in this page.

instance_offsetquery · integer

Number of matching instances to skip.

instance_qquery · string

Case-insensitive literal substring of the instance name.

instance_statusquery · enum

Filter by whether an instance is enabled or disabled, independently of its credentials.

One of active, disabled
provisioner_limitquery · integer

Number of provisioner tokens in this page, sorted by issued time and id, newest first.

provisioner_offsetquery · integer

Number of matching provisioner tokens to skip.

provisioner_qquery · string

Case-insensitive literal substring of the token identifier or displayed identifier suffix. Searches identifiers, never secrets.

provisioner_statusquery · enum

Token state, with revocation taking precedence over expiry.

One of active, expired, revoked

Response

Response codes

StatusBodyDescription
200Agent

The agent

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

You cannot read agents

404ErrorResponse

No such agent

Response body200

slugstringrequired

The agent's identity, chosen once at creation. It never changes and is never reused, not even after the agent is archived.

organization_iduuidrequired

The membership or organization-key actor that created the agent.

namestringrequired

The display name. Reviewers see it on every request. Editable, and unique among the organization's live agents.

statusenumrequired

A disabled agent's instances cannot authenticate until it is enabled again. An archived agent is retired: nothing of it authenticates, nothing can be enrolled under it, and its status cannot change until it is restored.

One of active, disabled, archived

created_atdate-timerequired
updated_atdate-timerequired
archived_atdate-time

When the agent was archived. Present exactly when status is archived.

provisioner_countintegerrequired

All provisioner tokens owned by this agent.

Tokens matching the current identifier and status filters before pagination.

instance_countintegerrequired

All instances owned by this agent.

live_instance_countintegerrequired

Active instances with at least one live credential across all pages.

Instances matching the current search and status filters before pagination.

request_countintegerrequired

All requests made by this agent.

One of human, api_key

The name of the human or organization key that created the agent.

instancesarray<AgentInstance>required

The requested page of instances, sorted by last seen, creation time, and id, newest first.

The requested page of provisioner tokens, sorted by issued time and id, newest first. Secrets are never included.

recent_request_countintegerrequired

Requests made in the last seven days.

pending_request_countintegerrequired

Requests still waiting for a decision.

Example

GET /api/v1/agents/{slug}
curl -X GET "$WITHHUMAN_URL/api/v1/agents/{slug}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "slug": "support-bot",
  "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "name": "Support bot",
  "status": "active",
  "created_at": "2026-09-08T12:02:11Z",
  "updated_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z",
  "provisioner_count": 0,
  "matching_provisioner_count": 0,
  "instance_count": 0,
  "live_instance_count": 0,
  "matching_instance_count": 0,
  "request_count": 0,
  "created_by_actor_type": "human",
  "created_by_display_name": "string",
  "instances": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "agent_slug": "string",
      "name": "ci-runner-07",
      "status": "active",
      "metadata": {
        "region": "eu-west"
      },
      "created_at": "2026-09-08T12:02:11Z",
      "last_seen_at": "2026-09-08T12:02:11Z",
      "credentials": [
        {
          "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
          "issued_at": "2026-09-08T12:02:11Z",
          "expires_at": "2026-09-08T12:02:11Z",
          "last_used_at": "2026-09-08T12:02:11Z",
          "revoked_at": "2026-09-08T12:02:11Z"
        }
      ],
      "recent_request_count": 0,
      "request_trend": [
        0
      ]
    }
  ],
  "provisioners": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "agent_slug": "string",
      "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "issued_at": "2026-09-08T12:02:11Z",
      "expires_at": "2026-09-08T12:02:11Z",
      "last_used_at": "2026-09-08T12:02:11Z",
      "revoked_at": "2026-09-08T12:02:11Z"
    }
  ],
  "recent_request_count": 0,
  "pending_request_count": 0
}

Update an agent

PATCH/api/v1/agents/{slug}Session or API keyRequires agent.write

Changes an agent's status or its display name, the two fields that can change after creation. The slug never changes. Who manages an agent is decided by the role assignments at the agent, not by a property of it.

Disabling an agent keeps its instances and credentials in place, but none of them can authenticate until the agent is enabled again. An archived agent is past both switches; restore it first.

Request

Parameters

ParameterTypeDescription
slugrequiredpath · string

The agent's slug: the identity chosen when it was created, never changed and never reused.

Request body

statusenum

active or disabled.

One of active, disabled

namestring

A new display name, unique among the organization's live agents. Audited as agent.renamed.

Response

Response codes

StatusBodyDescription
200Agent

The updated agent

400ErrorResponse

Neither status nor name was given, or the status is invalid

403ErrorResponse

You cannot change agents

404ErrorResponse

No such agent

409ErrorResponse

The agent is archived (agent_archived), or a live agent already has the name (agent_name_taken)

Response body200

slugstringrequired

The agent's identity, chosen once at creation. It never changes and is never reused, not even after the agent is archived.

organization_iduuidrequired

The membership or organization-key actor that created the agent.

namestringrequired

The display name. Reviewers see it on every request. Editable, and unique among the organization's live agents.

statusenumrequired

A disabled agent's instances cannot authenticate until it is enabled again. An archived agent is retired: nothing of it authenticates, nothing can be enrolled under it, and its status cannot change until it is restored.

One of active, disabled, archived

created_atdate-timerequired
updated_atdate-timerequired
archived_atdate-time

When the agent was archived. Present exactly when status is archived.

Example

PATCH /api/v1/agents/{slug}
curl -X PATCH "$WITHHUMAN_URL/api/v1/agents/{slug}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "active",
  "name": "Support bot"
}'
200 response
{
  "slug": "support-bot",
  "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "name": "Support bot",
  "status": "active",
  "created_at": "2026-09-08T12:02:11Z",
  "updated_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z"
}

Archive an agent

DELETE/api/v1/agents/{slug}Session or API keyRequires agent.write

Archives the agent. Every live credential and provisioner token is revoked. Nothing is deleted: the agent is still listed with status=archived or all, it can still be retrieved with its instances and revoked credentials, and its requests and audit trail stay readable. But no instance or provisioner token can be created for it and its status cannot change. Its name is freed for a new agent; its slug is not, and never will be.

The agent's approval pipeline is archived with it: every revision is stamped and the active one deactivated. The archived revisions stay readable but cannot be activated. Restore the agent to bring the pipeline back.

Request

Parameters

ParameterTypeDescription
slugrequiredpath · string

The agent's slug: the identity chosen when it was created, never changed and never reused.

Response

Response codes

StatusBodyDescription
204

The agent is archived

401ErrorResponse

You are not signed in

403ErrorResponse

You cannot change agents

404ErrorResponse

No such agent

409ErrorResponse

The agent is already archived (agent_archived)

Example

DELETE /api/v1/agents/{slug}
curl -X DELETE "$WITHHUMAN_URL/api/v1/agents/{slug}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"

Restore an archived agent

POST/api/v1/agents/{slug}/restoreSession or API keyRequires agent.write

Brings an archived agent back to active, together with its approval pipeline: every archived revision is unfrozen and the latest one becomes active again. Credentials and provisioner tokens revoked when the agent was archived stay revoked; register instances or connect them again to let it call the API. The name must still be free among the organization's live agents.

Request

Parameters

ParameterTypeDescription
slugrequiredpath · string

The agent's slug: the identity chosen when it was created, never changed and never reused.

Response

Response codes

StatusBodyDescription
200Agent

The restored agent

401ErrorResponse

You are not signed in

403ErrorResponse

You cannot change agents

404ErrorResponse

No such agent

409ErrorResponse

The agent is not archived (agent_not_archived), or a live agent took its name meanwhile (agent_name_taken)

Response body200

slugstringrequired

The agent's identity, chosen once at creation. It never changes and is never reused, not even after the agent is archived.

organization_iduuidrequired

The membership or organization-key actor that created the agent.

namestringrequired

The display name. Reviewers see it on every request. Editable, and unique among the organization's live agents.

statusenumrequired

A disabled agent's instances cannot authenticate until it is enabled again. An archived agent is retired: nothing of it authenticates, nothing can be enrolled under it, and its status cannot change until it is restored.

One of active, disabled, archived

created_atdate-timerequired
updated_atdate-timerequired
archived_atdate-time

When the agent was archived. Present exactly when status is archived.

Example

POST /api/v1/agents/{slug}/restore
curl -X POST "$WITHHUMAN_URL/api/v1/agents/{slug}/restore" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "slug": "support-bot",
  "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "name": "Support bot",
  "status": "active",
  "created_at": "2026-09-08T12:02:11Z",
  "updated_at": "2026-09-08T12:02:11Z",
  "archived_at": "2026-09-08T12:02:11Z"
}

Disable or enable an instance

PATCH/api/v1/agent_instances/{id}Session or API keyRequires agent.write

Disables or re-enables one instance. A disabled instance keeps its credentials, but none of them can authenticate until it is enabled again. The agent and its other instances are not affected.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The instance's id.

Request body

statusenumrequired

active or disabled.

One of active, disabled

Response

Response codes

StatusBodyDescription
200AgentInstance

The updated instance

400ErrorResponse

status is not active or disabled

403ErrorResponse

You cannot change agents

404ErrorResponse

No such instance

409ErrorResponse

The instance's agent is archived (agent_archived)

Response body200

iduuidrequired
organization_iduuidrequired
agent_slugstringrequired

The slug of the agent this is an instance of.

namestringrequired

Unique within the agent.

statusenumrequired

A disabled instance cannot create requests.

One of active, disabled

metadataobjectrequired

The JSON stored when the instance was created.

created_atdate-timerequired
last_seen_atdate-timerequired

The last time this instance called the API.

Example

PATCH /api/v1/agent_instances/{id}
curl -X PATCH "$WITHHUMAN_URL/api/v1/agent_instances/{id}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "status": "active"
}'
200 response
{
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "agent_slug": "string",
  "name": "ci-runner-07",
  "status": "active",
  "metadata": {
    "region": "eu-west"
  },
  "created_at": "2026-09-08T12:02:11Z",
  "last_seen_at": "2026-09-08T12:02:11Z"
}

Register an instance

POST/api/v1/agents/{slug}/instancesSession or API keyRequires agent.credential.issue

Registers an instance of an agent and issues its credential. An instance is one running copy of the agent, such as a CI runner or a pod. The credential's token is returned once, in this response. Store it where the instance can read it. It cannot be retrieved again.

Use this when you set up an instance by hand. For a fleet that starts replicas itself, create a provisioner token instead and let each replica create its own instance through the Agent Approval Protocol (AAP).

Request

Parameters

ParameterTypeDescription
slugrequiredpath · string

The agent's slug: the identity chosen when it was created, never changed and never reused.

Request body

namestringrequired

A name for the instance, unique within the agent. Reviewers see it next to the agent's name.

metadataobject

Any JSON object to store with the instance, such as a region or pod name.

Response

Response codes

StatusBodyDescription
201AgentInstanceCredential

The new instance and its credential. The token appears only in this response.

403ErrorResponse

You cannot issue credentials

404ErrorResponse

No such agent

409ErrorResponse

The agent is archived (agent_archived)

Response body201

One running copy of an agent.

Example

POST /api/v1/agents/{slug}/instances
curl -X POST "$WITHHUMAN_URL/api/v1/agents/{slug}/instances" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "ci-runner-07",
  "metadata": {
    "region": "eu-west"
  }
}'
201 response
{
  "agent_instance": {
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "agent_slug": "string",
    "name": "ci-runner-07",
    "status": "active",
    "metadata": {
      "region": "eu-west"
    },
    "created_at": "2026-09-08T12:02:11Z",
    "last_seen_at": "2026-09-08T12:02:11Z"
  },
  "credential": {
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "token": "whc_live_3f6b9c1d0e7a4b2c",
    "expires_at": "2026-09-08T12:02:11Z"
  }
}

Create a provisioner token

POST/api/v1/agents/{slug}/provisionersSession or API keyRequires agent.credential.issue

Creates a provisioner token for an agent. A provisioner token lets a fleet or platform create instances of this agent on its own, each with a credential of its own, through the Agent Approval Protocol (AAP). It cannot create approval requests itself.

The token is returned once, in this response. It cannot be retrieved again.

Request

Parameters

ParameterTypeDescription
slugrequiredpath · string

The agent's slug: the identity chosen when it was created, never changed and never reused.

Response

Response codes

StatusBodyDescription
201AgentProvisionerCredential

The provisioner and its token. The token appears only in this response.

403ErrorResponse

You cannot issue credentials

404ErrorResponse

No such agent

409ErrorResponse

The agent is archived (agent_archived)

Response body201

A provisioner token as the agent page shows it. The token is never included.

Example

POST /api/v1/agents/{slug}/provisioners
curl -X POST "$WITHHUMAN_URL/api/v1/agents/{slug}/provisioners" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
201 response
{
  "provisioner": {
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "organization_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "agent_slug": "string",
    "created_by_actor_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "issued_at": "2026-09-08T12:02:11Z",
    "expires_at": "2026-09-08T12:02:11Z",
    "last_used_at": "2026-09-08T12:02:11Z",
    "revoked_at": "2026-09-08T12:02:11Z"
  },
  "credential": {
    "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
    "token": "whc_live_3f6b9c1d0e7a4b2c",
    "expires_at": "2026-09-08T12:02:11Z"
  }
}

Revoke a provisioner token

DELETE/api/v1/agent-provisioners/{id}Session or API keyRequires agent.credential.revoke

Revokes a provisioner token. It stops working immediately. The instances it already created, and their credentials, are not affected.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The provisioner's id.

Response

Response codes

StatusBodyDescription
204

The token is revoked

403ErrorResponse

You cannot revoke credentials

404ErrorResponse

No such provisioner

Example

DELETE /api/v1/agent-provisioners/{id}
curl -X DELETE "$WITHHUMAN_URL/api/v1/agent-provisioners/{id}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"

Revoke a credential

DELETE/api/v1/agent-credentials/{id}Session or API keyRequires agent.credential.revoke

Revokes one instance credential. It stops working immediately. The instance stays registered, and the agent and its other instances are not affected.

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid

The credential's id.

Response

Response codes

StatusBodyDescription
204

The credential is revoked

403ErrorResponse

You cannot revoke credentials

404ErrorResponse

No such credential

Example

DELETE /api/v1/agent-credentials/{id}
curl -X DELETE "$WITHHUMAN_URL/api/v1/agent-credentials/{id}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"

Report the calling instance's tool catalogue

PUT/api/v1/agent_instances/self/tool_catalogBearer tokenSelf-service

Replaces complete source snapshots in one discovery context. Failed sources retain their last successful definitions. The instance credential supplies organization and instance identity. No arguments or credentials belong in a report. This product endpoint is outside AAP. Maximum body size is 8 MiB.

Request

Request body

runtimestringrequired
discovery_contextstringrequired

Stable opaque identifier for this local project or runtime context

completebooleanrequired

Whether all configured sources in this context were enumerated

Response

Response codes

StatusBodyDescription
204

Catalogue report recorded

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Example

PUT /api/v1/agent_instances/self/tool_catalog
curl -X PUT "$WITHHUMAN_URL/api/v1/agent_instances/self/tool_catalog" \
  -H "Authorization: Bearer $WITHHUMAN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "runtime": "string",
  "discovery_context": "string",
  "complete": true,
  "sources": [
    {
      "source": "builtin",
      "server": "string",
      "complete": true,
      "error": "string",
      "tools": [
        {
          "name": "string",
          "display_name": "string",
          "description": "string",
          "input_schema": {},
          "annotations": {
            "title": "string",
            "read_only_hint": true,
            "destructive_hint": true,
            "idempotent_hint": true,
            "open_world_hint": true
          }
        }
      ]
    }
  ]
}'

List known tool definitions

GET/api/v1/tool_catalogSession or API keyRequires agent.read

Returns definitions within the caller's agent scope. An edition's own tool source (the hosted gateway) is refreshed on read through a five-minute shared cache, with that edition's live grants applied. Failed refreshes retain the last successful definitions and mark their source stale. Catalogue information is advisory and never changes approval decisions.

Request

Parameters

ParameterTypeDescription
agent_slugquery · string
qquery · string
sourcequery · string

Only tools from this source: builtin, mcp, or a source an edition adds (the hosted gateway's gateway).

statusquery · enum
One of available, unavailable, stale
limitquery · integer
offsetquery · integer
refreshquery · boolean

Bypass the edition's tool source discovery cache. Local tools require a CLI report.

Response

Response codes

StatusBodyDescription
200ToolCatalogPage

Known definitions and source discovery status

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

totalintegerrequired
next_offsetintegerrequired

Example

GET /api/v1/tool_catalog
curl -X GET "$WITHHUMAN_URL/api/v1/tool_catalog" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "tools": [
    {
      "name": "string",
      "display_name": "string",
      "description": "string",
      "input_schema": {},
      "annotations": {
        "title": "string",
        "read_only_hint": true,
        "destructive_hint": true,
        "idempotent_hint": true,
        "open_world_hint": true
      },
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "agent_slug": "string",
      "agent_instance_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "instance_name": "string",
      "discovery_context": "string",
      "runtime": "string",
      "source": "string",
      "server": "string",
      "available": true,
      "stale": true,
      "error": "string",
      "schema_fingerprint": "string",
      "last_seen_at": "2026-09-08T12:02:11Z",
      "last_attempt_at": "2026-09-08T12:02:11Z"
    }
  ],
  "sources": [
    {
      "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "agent_slug": "string",
      "agent_instance_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "runtime": "string",
      "discovery_context": "string",
      "source": "string",
      "server": "string",
      "last_attempt_at": "2026-09-08T12:02:11Z",
      "last_success_at": "2026-09-08T12:02:11Z",
      "error": "string"
    }
  ],
  "total": 0,
  "next_offset": 1
}

Read a tool definition

GET/api/v1/tool_catalog/{id}Session or API keyRequires agent.read

Request

Parameters

ParameterTypeDescription
idrequiredpath · uuid
agent_slugquery · string

Response

Response codes

StatusBodyDescription
200ToolCatalogEntryDefinition

Definition and its discovery provenance

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

namestringrequired
iduuidrequired
agent_slugstringrequired
discovery_contextstringrequired
runtimestringrequired
sourcestringrequired

builtin, mcp, or a source an edition adds (the hosted gateway's gateway)

serverstring
availablebooleanrequired
stalebooleanrequired
errorstring
schema_fingerprintstringrequired
last_seen_atdate-timerequired
last_attempt_atdate-timerequired

Example

GET /api/v1/tool_catalog/{id}
curl -X GET "$WITHHUMAN_URL/api/v1/tool_catalog/{id}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "name": "string",
  "display_name": "string",
  "description": "string",
  "input_schema": {},
  "annotations": {
    "title": "string",
    "read_only_hint": true,
    "destructive_hint": true,
    "idempotent_hint": true,
    "open_world_hint": true
  },
  "id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "agent_slug": "string",
  "agent_instance_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "instance_name": "string",
  "discovery_context": "string",
  "runtime": "string",
  "source": "string",
  "server": "string",
  "available": true,
  "stale": true,
  "error": "string",
  "schema_fingerprint": "string",
  "last_seen_at": "2026-09-08T12:02:11Z",
  "last_attempt_at": "2026-09-08T12:02:11Z"
}

Read an agent's gateway tool accessHosted edition

GET/api/v1/agents/{slug}/tool-accessSession or API keyRequires gateway.read

Requires gateway.read and agent.read for the named agent. Unconfigured servers grant no access. All instances inherit these grants.

Request

Parameters

ParameterTypeDescription
slugrequiredpath · string

Response

Response codes

StatusBodyDescription
200object

Saved grants, including no-access grants retained for revision checks

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

501ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

grantsarray<AgentToolAccess>required

Example

GET /api/v1/agents/{slug}/tool-access
curl -X GET "$WITHHUMAN_URL/api/v1/agents/{slug}/tool-access" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY"
200 response
{
  "grants": [
    {
      "server_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
      "server_slug": "string",
      "mode": "none",
      "tools": [
        "string"
      ],
      "revision": 1
    }
  ]
}

Replace an agent's access to a server's toolsHosted edition

PUT/api/v1/agents/{slug}/tool-access/{server_slug}Session or API keyRequires gateway.write

Requires gateway.write and agent.read for the named agent. Grants exact tool names on this server, all current and future tools, or no tools. Supply the current revision, or zero for an unconfigured pair. A stale revision returns 412; an identical retry of the last write returns its committed result without another audit event. This version is the retry identity, so no Idempotency-Key is required. Archived agents and servers refuse edits. Inactive servers can be configured. The next MCP tool listing reflects changes; calls check live access before execution, including after approval. Already dispatched calls cannot be undone.

Request

Parameters

ParameterTypeDescription
slugrequiredpath · string
server_slugrequiredpath · string

Request body

modeenumrequired

One of none, selected, all

toolsarray<string>required

Exact downstream tool names, meaningful only in selected mode. Empty for none or all; no wildcard matching.

revisionint64required

Expected current version; zero for an unconfigured agent/server pair.

Response

Response codes

StatusBodyDescription
200AgentToolAccess

Saved grant with its new revision

400ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

401ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

403ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

404ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

409ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

412ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

501ErrorResponse

Error response. A 403 from a permission check carries ForbiddenDetails in error.details.

Response body200

server_iduuidrequired
server_slugstringrequired
modeenumrequired

One of none, selected, all

toolsarray<string>required
revisionint64required

Example

PUT /api/v1/agents/{slug}/tool-access/{server_slug}
curl -X PUT "$WITHHUMAN_URL/api/v1/agents/{slug}/tool-access/{server_slug}" \
  -H "Authorization: Bearer $WITHHUMAN_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "mode": "none",
  "tools": [
    "string"
  ],
  "revision": 0
}'
200 response
{
  "server_id": "7ab8c8ec-7b2d-4fd6-9b52-752f9515eb71",
  "server_slug": "string",
  "mode": "none",
  "tools": [
    "string"
  ],
  "revision": 1
}