Proxy API

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.

Reference a credential by name. The proxy handles routing and auth injection automatically.

Headers:

HeaderRequiredDescription
X-TAP-KeyyesAgent API key
X-TAP-CredentialyesCredential name
X-TAP-TargetyesTarget API URL (or path if relative_target is set)
X-TAP-MethodnoHTTP method to use upstream (default: GET in unified mode, POST in legacy mode)
X-TAP-TeamnoTeam 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

StatusMeaning
400Invalid request (missing headers, placeholder in non-auth position)
401Invalid or missing X-TAP-Key
403Credential not whitelisted for this agent, or approval denied
429Rate limit exceeded
502Upstream API error
504Approval 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:

ParamDefaultMaxDescription
limit20100Number 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/health

Returns 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 hyphens
  • email: 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"
}
FieldRequiredDefaultDescription
nameyesCredential identifier
descriptionyesHuman-readable description
connectorno"direct""direct" (API key injection) or "sidecar" (external service)
api_basenoBase URL for the target API or sidecar
relative_targetnofalseIf true, X-TAP-Target is a path appended to api_base
auth_header_formatnoFormat string for the Authorization header (e.g., "Bearer {value}")
valuenoThe 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
}
FieldRequiredDescription
idyesAgent identifier
descriptionnoHuman-readable description
rolesnoList of role names to assign
credentialsnoList of credential names for direct access
rate_limit_per_hournoMax 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"
}
FieldDescription
auto_approve_methodsHTTP methods that skip approval
require_approval_methodsHTTP methods that require human approval
auto_approve_urlsURL substrings that skip approval regardless of method
allowed_approversTelegram user IDs allowed to approve (empty = anyone)
telegram_chat_idOverride 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 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.

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"