API Reference
TAP exposes three groups of endpoints: agent endpoints (authenticated via X-TAP-Key), admin auth endpoints (public), and admin CRUD endpoints (authenticated via Authorization: Bearer <session_token>).
Agent Endpoints
These endpoints are used by AI agents. All except /health require the X-TAP-Key header.
POST /forward
The core proxy endpoint. Authenticates the agent, evaluates policy, requests approval if needed, injects credentials, forwards the request, and sanitizes the response.
Unified Mode (Recommended)
Reference a credential by name. The proxy handles routing and auth injection automatically.
Headers:
| Header | Required | Description |
|---|---|---|
X-TAP-Key | yes | Agent API key |
X-TAP-Credential | yes | Credential name |
X-TAP-Target | yes | Target API URL (or path if relative_target is set) |
X-TAP-Method | no | HTTP method to use upstream (default: GET in unified mode, POST in legacy mode) |
X-TAP-Team | no | Team ID for cross-team credential access (multi-account) |
Example — auto-approved GET:
curl -X POST https://proxy.toolsec.org/forward \
-H "X-TAP-Key: $MY_KEY" \
-H "X-TAP-Credential: slack" \
-H "X-TAP-Target: https://slack.com/api/conversations.list" \
-H "X-TAP-Method: GET"Example — POST requiring approval:
curl -X POST https://proxy.toolsec.org/forward \
-H "X-TAP-Key: $MY_KEY" \
-H "X-TAP-Credential: slack" \
-H "X-TAP-Target: https://slack.com/api/chat.postMessage" \
-H "X-TAP-Method: POST" \
-H "Content-Type: application/json" \
-d '{"channel": "C123456", "text": "Hello from my agent"}'The request blocks until approved/denied in Telegram or times out (default 5 minutes).
Example — cross-team credential access:
curl -X POST https://proxy.toolsec.org/forward \
-H "X-TAP-Key: $MY_KEY" \
-H "X-TAP-Credential: github" \
-H "X-TAP-Target: https://api.github.com/repos/org/repo/issues" \
-H "X-TAP-Method: GET" \
-H "X-TAP-Team: other-team-id"Example — sidecar with relative target:
curl -X POST https://proxy.toolsec.org/forward \
-H "X-TAP-Key: $MY_KEY" \
-H "X-TAP-Credential: telegram" \
-H "X-TAP-Target: /sendMessage" \
-H "X-TAP-Method: POST" \
-H "Content-Type: application/json" \
-d '{"chat_id": "123", "text": "Hello"}'Legacy Placeholder Mode
Use <CREDENTIAL:name> placeholders in headers or body. The proxy validates placeholder positions, then substitutes real values after approval.
curl -X POST https://proxy.toolsec.org/forward \
-H "X-TAP-Key: $MY_KEY" \
-H "X-TAP-Target: https://api.openai.com/v1/chat/completions" \
-H "Authorization: Bearer <CREDENTIAL:openai-key>" \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4", "messages": [{"role": "user", "content": "Hello"}]}'Placeholders are only allowed in auth-related positions. The proxy rejects requests where credentials appear in non-auth positions (tweet text, email body, etc.) to prevent exfiltration.
Error Responses
| Status | Meaning |
|---|---|
| 400 | Invalid request (missing headers, placeholder in non-auth position) |
| 401 | Invalid or missing X-TAP-Key |
| 403 | Credential not whitelisted for this agent, or approval denied |
| 429 | Rate limit exceeded |
| 502 | Upstream API error |
| 504 | Approval timed out |
All errors return JSON:
{"error": "description of what went wrong"}GET /agent/services
Returns available services for the authenticated agent, including linked teams for multi-account setups.
curl https://proxy.toolsec.org/agent/services \
-H "X-TAP-Key: $MY_KEY"Response:
{
"agent_id": "my-agent",
"home_team_id": "abc-123",
"services": {
"slack": {
"description": "Slack API",
"reads_auto_approved": true,
"writes_need_approval": true,
"target_base": "https://slack.com/api"
}
},
"linked_teams": [
{
"team_id": "other-team-456",
"role": "reader"
}
],
"usage": {
"method": "POST /forward",
"headers": {
"X-TAP-Key": "<your-key>",
"X-TAP-Credential": "<service-name>",
"X-TAP-Target": "<api-url-or-path>",
"X-TAP-Method": "GET|POST|PUT|PATCH|DELETE",
"X-TAP-Team": "(optional) team-id for cross-team credential access"
}
}
}Internal details (sidecar URLs, connector types) are hidden from agents.
GET /agent/logs
Returns recent audit log entries for the authenticated agent.
curl "https://proxy.toolsec.org/agent/logs?limit=5" \
-H "X-TAP-Key: $MY_KEY"Query parameters:
| Param | Default | Max | Description |
|---|---|---|---|
limit | 20 | 100 | Number of entries to return |
Response:
{
"agent_id": "my-agent",
"count": 1,
"entries": [
{
"request_id": "550e8400-e29b-41d4-a716-446655440000",
"agent_id": "my-agent",
"credential_names": ["slack"],
"target_url": "https://slack.com/api/conversations.list",
"method": "GET",
"approval_status": "AutoApproved",
"upstream_status": 200,
"total_latency_ms": 145,
"approval_latency_ms": 0,
"upstream_latency_ms": 120,
"response_sanitized": false,
"timestamp": "2026-03-30T14:22:15.123Z"
}
]
}GET /agent/config
Returns the credential list for the authenticated agent.
curl https://proxy.toolsec.org/agent/config \
-H "X-TAP-Key: $MY_KEY"Response:
{
"agent_id": "my-agent",
"credentials": [
{
"name": "slack",
"description": "Slack API",
"api_base": "https://slack.com/api"
}
]
}GET /health
Health check endpoint. No authentication required.
curl https://proxy.toolsec.org/healthReturns 200 OK with {"status": "ok"} when the proxy is running.
Admin Auth Endpoints
These endpoints handle team signup, email verification, login, and logout. No authentication is required for signup and login.
POST /signup
Create a new team and admin account.
Body:
{
"team_name": "my-team",
"email": "admin@example.com",
"password": "a-strong-password"
}Validation:
team_name: 3-64 characters, lowercase alphanumeric with hyphensemail: must contain@and.password: minimum 8 characters
Response (201):
{
"team_id": "550e8400-e29b-41d4-a716-446655440000",
"team_name": "my-team",
"admin_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"message": "Verification email sent. Check your inbox."
}curl example:
curl -X POST https://proxy.toolsec.org/signup \
-H "Content-Type: application/json" \
-d '{"team_name": "my-team", "email": "admin@example.com", "password": "my-password"}'POST /verify-email
Verify email address with the 6-digit code sent during signup.
Body:
{
"email": "admin@example.com",
"code": "123456"
}Response (200):
{"verified": true}POST /login
Authenticate with email and password. Returns a session token valid for 24 hours.
Body:
{
"email": "admin@example.com",
"password": "my-password"
}Response (200):
{
"session_token": "a1b2c3d4e5f6...",
"admin_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"team_id": "550e8400-e29b-41d4-a716-446655440000",
"expires_at": "2026-04-03T14:00:00Z"
}curl example:
curl -X POST https://proxy.toolsec.org/login \
-H "Content-Type: application/json" \
-d '{"email": "admin@example.com", "password": "my-password"}'POST /logout
Invalidate the current session.
Header: Authorization: Bearer <session_token>
curl -X POST https://proxy.toolsec.org/logout \
-H "Authorization: Bearer $SESSION_TOKEN"Response (200):
{"logged_out": true}Admin CRUD Endpoints
All admin CRUD endpoints require Authorization: Bearer <session_token>. Operations are scoped to the admin’s team — you can only manage resources within your own team.
Credentials
Credential values are write-only. They are never returned by any API endpoint.
GET /admin/credentials
List all credentials for your team.
curl https://proxy.toolsec.org/admin/credentials \
-H "Authorization: Bearer $SESSION_TOKEN"Response:
{
"credentials": [
{
"name": "slack",
"description": "Slack API",
"connector": "direct",
"api_base": "https://slack.com/api",
"relative_target": false,
"has_value": true
}
]
}POST /admin/credentials
Create a new credential.
Body:
{
"name": "slack",
"description": "Slack API",
"connector": "direct",
"api_base": "https://slack.com/api",
"relative_target": false,
"auth_header_format": "Bearer {value}",
"value": "xoxb-your-slack-token"
}| Field | Required | Default | Description |
|---|---|---|---|
name | yes | Credential identifier | |
description | yes | Human-readable description | |
connector | no | "direct" | "direct" (API key injection) or "sidecar" (external service) |
api_base | no | Base URL for the target API or sidecar | |
relative_target | no | false | If true, X-TAP-Target is a path appended to api_base |
auth_header_format | no | Format string for the Authorization header (e.g., "Bearer {value}") | |
value | no | The secret credential value (write-only, never returned) |
curl example:
curl -X POST https://proxy.toolsec.org/admin/credentials \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"name": "slack",
"description": "Slack API",
"connector": "direct",
"api_base": "https://slack.com/api",
"value": "xoxb-your-slack-token"
}'Response (201):
{"name": "slack", "created": true}DELETE /admin/credentials/:name
Delete a credential.
curl -X DELETE https://proxy.toolsec.org/admin/credentials/slack \
-H "Authorization: Bearer $SESSION_TOKEN"Agents
GET /admin/agents
List all agents in your team.
curl https://proxy.toolsec.org/admin/agents \
-H "Authorization: Bearer $SESSION_TOKEN"Response:
{
"agents": [
{
"id": "research-bot",
"description": "Research assistant",
"enabled": true,
"rate_limit_per_hour": 100,
"created_at": "2026-04-01T10:00:00Z"
}
]
}POST /admin/agents
Create an agent. The API key is returned once and cannot be retrieved again.
Body:
{
"id": "research-bot",
"description": "Research assistant",
"roles": ["reader"],
"credentials": ["slack"],
"rate_limit_per_hour": 100
}| Field | Required | Description |
|---|---|---|
id | yes | Agent identifier |
description | no | Human-readable description |
roles | no | List of role names to assign |
credentials | no | List of credential names for direct access |
rate_limit_per_hour | no | Max requests per hour (null = unlimited) |
curl example:
curl -X POST https://proxy.toolsec.org/admin/agents \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"id": "research-bot",
"description": "Research assistant",
"roles": ["reader"],
"credentials": ["slack"],
"rate_limit_per_hour": 100
}'Response (201):
{
"id": "research-bot",
"api_key": "a1b2c3d4e5f6...",
"message": "Save this API key — it will not be shown again."
}GET /admin/agents/:id
Get agent details including effective credentials (union of role credentials and direct assignments).
curl https://proxy.toolsec.org/admin/agents/research-bot \
-H "Authorization: Bearer $SESSION_TOKEN"Response:
{
"id": "research-bot",
"description": "Research assistant",
"enabled": true,
"rate_limit_per_hour": 100,
"created_at": "2026-04-01T10:00:00Z",
"effective_credentials": ["github", "slack"]
}DELETE /admin/agents/:id
curl -X DELETE https://proxy.toolsec.org/admin/agents/research-bot \
-H "Authorization: Bearer $SESSION_TOKEN"POST /admin/agents/:id/enable
Re-enable a disabled agent.
curl -X POST https://proxy.toolsec.org/admin/agents/research-bot/enable \
-H "Authorization: Bearer $SESSION_TOKEN"POST /admin/agents/:id/disable
Disable an agent. All requests from this agent will be rejected until re-enabled.
curl -X POST https://proxy.toolsec.org/admin/agents/research-bot/disable \
-H "Authorization: Bearer $SESSION_TOKEN"Roles
Roles provide RBAC for credential access. An agent’s effective permissions are the union of all its roles’ credentials plus its direct credential assignments.
GET /admin/roles
curl https://proxy.toolsec.org/admin/roles \
-H "Authorization: Bearer $SESSION_TOKEN"Response:
{
"roles": [
{
"name": "reader",
"description": "Read-only API access",
"rate_limit_per_hour": 50
}
]
}POST /admin/roles
Create a role with optional initial credentials.
Body:
{
"name": "reader",
"description": "Read-only API access",
"credentials": ["slack", "github"],
"rate_limit_per_hour": 50
}curl -X POST https://proxy.toolsec.org/admin/roles \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"name": "reader", "description": "Read-only access", "credentials": ["slack", "github"]}'DELETE /admin/roles/:name
Delete a role. Cascades — removes the role from all agents.
curl -X DELETE https://proxy.toolsec.org/admin/roles/reader \
-H "Authorization: Bearer $SESSION_TOKEN"Policies
Policies control per-credential approval behavior. See Policies & Approval for details on evaluation order.
GET /admin/policies/:cred_name
curl https://proxy.toolsec.org/admin/policies/slack \
-H "Authorization: Bearer $SESSION_TOKEN"Response:
{
"credential": "slack",
"auto_approve_methods": ["GET", "HEAD"],
"require_approval_methods": ["POST", "PUT", "DELETE"],
"auto_approve_urls": ["/conversations.list", "/users.list"],
"allowed_approvers": ["123456789"],
"telegram_chat_id": "-100123456789"
}Returns 404 if no policy is set for the credential.
PUT /admin/policies/:cred_name
Set or update the policy for a credential.
Body:
{
"auto_approve_methods": ["GET", "HEAD"],
"require_approval_methods": ["POST", "PUT", "DELETE"],
"auto_approve_urls": ["/conversations.list"],
"allowed_approvers": ["123456789"],
"telegram_chat_id": "-100123456789"
}| Field | Description |
|---|---|
auto_approve_methods | HTTP methods that skip approval |
require_approval_methods | HTTP methods that require human approval |
auto_approve_urls | URL substrings that skip approval regardless of method |
allowed_approvers | Telegram user IDs allowed to approve (empty = anyone) |
telegram_chat_id | Override the default Telegram chat for this credential |
curl example:
curl -X PUT https://proxy.toolsec.org/admin/policies/slack \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"auto_approve_methods": ["GET"],
"require_approval_methods": ["POST", "PUT", "DELETE"],
"auto_approve_urls": ["/conversations.list", "/users.list"]
}'Team
GET /admin/team
Get your team information.
curl https://proxy.toolsec.org/admin/team \
-H "Authorization: Bearer $SESSION_TOKEN"Response:
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "my-team",
"created_at": "2026-04-01T00:00:00Z"
}Agent Links (Multi-Account)
Agent links allow an agent from one team to access credentials in another team. The admin of the receiving team creates the link, granting a foreign agent access via an assigned role.
GET /admin/agent-links
List all foreign agents linked to your team.
curl https://proxy.toolsec.org/admin/agent-links \
-H "Authorization: Bearer $SESSION_TOKEN"Response:
{
"agent_links": [
{
"agent_home_team_id": "team-abc",
"agent_id": "research-bot",
"linked_team_id": "my-team-id",
"role": "reader",
"created_at": "2026-04-01T12:00:00Z"
}
]
}POST /admin/agent-links
Link an external agent to your team. The agent must exist in its home team.
Body:
{
"agent_home_team_id": "team-abc",
"agent_id": "research-bot",
"role": "reader"
}curl -X POST https://proxy.toolsec.org/admin/agent-links \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"agent_home_team_id": "team-abc", "agent_id": "research-bot", "role": "reader"}'Response (201):
{
"linked": true,
"agent_home_team_id": "team-abc",
"agent_id": "research-bot",
"linked_team_id": "my-team-id",
"role": "reader"
}DELETE /admin/agent-links/:home_team_id/:agent_id
Unlink a foreign agent from your team.
curl -X DELETE https://proxy.toolsec.org/admin/agent-links/team-abc/research-bot \
-H "Authorization: Bearer $SESSION_TOKEN"Notification Channels
Configure where approval requests are sent for your team.
GET /admin/notification-channels
curl https://proxy.toolsec.org/admin/notification-channels \
-H "Authorization: Bearer $SESSION_TOKEN"Response:
{
"notification_channels": [
{
"id": "ch-1",
"channel_type": "telegram",
"name": "ops-channel",
"config": {"chat_id": "-100123456789"},
"enabled": true,
"created_at": "2026-04-01T00:00:00Z"
}
]
}POST /admin/notification-channels
Create a notification channel. Currently supports telegram.
Body:
{
"channel_type": "telegram",
"name": "ops-channel",
"config": {"chat_id": "-100123456789"}
}curl -X POST https://proxy.toolsec.org/admin/notification-channels \
-H "Authorization: Bearer $SESSION_TOKEN" \
-H "Content-Type: application/json" \
-d '{"channel_type": "telegram", "name": "ops-channel", "config": {"chat_id": "-100123456789"}}'DELETE /admin/notification-channels/:name
curl -X DELETE https://proxy.toolsec.org/admin/notification-channels/ops-channel \
-H "Authorization: Bearer $SESSION_TOKEN"