# Tools

> The Tools operations of the Hub REST API (11 operations).

URL: https://docs.synap.live/docs/reference/hub-api/tools · Generated from Synap-core/backend@c31e261ab (main)

Paths are relative to `/api/hub` on a pod.

## GET /tools

List tools

Lists tools visible to the caller: pod-wide (null workspaceId) plus the given workspace. Requires hub-protocol.read scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `workspaceId` | query | string |  |  |
| `limit` | query | string |  |  |

Responses:

- `200`: Tool list
- `403`: Forbidden
- `500`: Internal error

## POST /tools

Create a tool (capability substrate)

Seeds a `tools` row — the agnostic integration registry. Proposal-gated: if the workspace governance requires review, returns status='proposed' with a proposalId instead of creating. Requires hub-protocol.write scope.

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string | yes |  |
| `kind` | "builtin" \| "api" \| "mcp" \| "provider" \| "external" \| "script" | yes |  |
| `description` | string |  |  |
| `inputSchema` | object |  |  |
| `credentialRef` | string |  |  |
| `executor` | "is-agent" \| "external-agent" \| "hybrid" |  |  |
| `config` | object |  |  |
| `workspaceId` | string |  |  |
| `agentUserId` | string |  |  |
| `source` | string |  |  |
| `reasoning` | string |  |  |

Responses:

- `200`: Created or proposed tool
- `400`: Bad request
- `403`: Forbidden
- `500`: Internal error

## GET /tools/{id}

Get a tool and the skills that require it

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Responses:

- `200`: Tool + requiring skills
- `403`: Forbidden
- `404`: Not found
- `500`: Internal error

## PATCH /tools/{id}

Update a tool (capability substrate)

Updates a `tools` row. Proposal-gated: returns status='proposed' with a proposalId when governance requires review. Changing execution-defining fields (credentialRef, config, executor, kind, inputSchema) resets approval to false. Pod-wide tools require pod-admin. Requires hub-protocol.write scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `name` | string |  |  |
| `description` | string |  |  |
| `credentialRef` | string |  |  |
| `config` | object |  |  |
| `metadata` | object |  |  |
| `executor` | "is-agent" \| "external-agent" \| "hybrid" |  |  |
| `kind` | "builtin" \| "api" \| "mcp" \| "provider" \| "external" \| "script" |  |  |
| `inputSchema` | object |  |  |
| `status` | "active" \| "inactive" \| "error" |  |  |

Responses:

- `200`: Updated or proposed tool
- `400`: Bad request
- `403`: Forbidden
- `404`: Not found
- `500`: Internal error

## DELETE /tools/{id}

Delete a tool (capability substrate)

Deletes a `tools` row. Proposal-gated: returns status='proposed' with a proposalId when governance requires review (AI-initiated deletes propose, human deletes execute). Requires hub-protocol.write scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Responses:

- `200`: Deleted or proposed
- `400`: Bad request
- `403`: Forbidden
- `404`: Not found
- `500`: Internal error

## POST /tools/{id}/webhook

Mint or return a tool's inbound webhook URL

For a tool whose provider calls the pod at /api/webhooks/<provider>/:token (postiz, cal.com, fireflies, mailgun): returns the full URL, minting the token on first call. Idempotent; `rotate:true` replaces the token. Gated on write access to the tool's own row. The URL carries a secret: show it to the person, never log it. Requires hub-protocol.write scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `rotate` | boolean |  |  |

Responses:

- `200`: The webhook URL
- `400`: Not a webhook tool
- `403`: Forbidden
- `404`: Not found
- `412`: Pod has no PUBLIC_URL
- `500`: Internal error

## POST /tools/{id}/approve

Approve or revoke a tool's execution

Sets the `approved` flag on a tool — the draft→approve→run gate. Owner-gated (workspace owner, or pod-admin for pod-wide tools) via the governed toolsRouter.setApproved. Requires hub-protocol.write scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `approved` | boolean |  |  |

Responses:

- `200`: Updated approval state
- `400`: Bad request
- `403`: Forbidden
- `404`: Not found
- `500`: Internal error

## POST /tools/{id}/auth-binding

Set a tool's dynamic auth binding

Sets the `authBinding` on a tool (static/per_user/per_agent/per_entity). Owner-gated: workspace owner, or pod-admin for pod-wide tools. Changing the binding resets approval. Requires hub-protocol.write scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `authBinding` | "static" \| "per_user" \| "per_agent" \| "per_entity" | yes |  |

Responses:

- `200`: Updated auth binding
- `400`: Bad request
- `403`: Forbidden
- `404`: Not found
- `500`: Internal error

## GET /tools/{id}/credentials

List bound credentials for a tool

Lists the connections (vault secrets) scoped to this tool's capability. Owner-gated. Requires hub-protocol.read scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Responses:

- `200`: Bound credential list
- `403`: Forbidden
- `404`: Not found
- `500`: Internal error

## POST /tools/{id}/credentials

Bind a credential to a principal/entity for a tool

Binds a vault secret to a principal (participant or entity) for this tool's capability, stamping the secret's connection context. Owner-gated. The secret must exist and belong to the acting user. Requires hub-protocol.write scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |

Request body (`application/json`): object

| Field | Type | Required | Description |
|---|---|---|---|
| `principalType` | "participant" \| "entity" | yes |  |
| `principalId` | string | yes |  |
| `secretId` | string | yes |  |

Responses:

- `200`: Bound credential link
- `400`: Bad request
- `403`: Forbidden
- `404`: Not found
- `500`: Internal error

## DELETE /tools/{id}/credentials/{linkId}

Unbind a credential from a tool

Clears a secret's connection context (the `linkId` path param is the secret id). Gated on secret ownership. Requires hub-protocol.write scope.

Parameters:

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `id` | path | string | yes |  |
| `linkId` | path | string | yes |  |

Responses:

- `200`: Credential unbound
- `400`: Bad request
- `403`: Forbidden
- `404`: Not found
- `500`: Internal error
