Veefore docs

Register a tool

Make your system something an agent can be authorized for — with its own destination allowlist, risk rating and egress guards.

A tool is a registered, callable thing: an endpoint, the capability it requires, the hosts it may contact, its risk rating, and whether it is dangerous. Agents can only call tools, and only tools they are explicitly authorized for.

#Register

bash
curl -X POST https://veefore.example.com/v1/tools \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -H 'Idempotency-Key: register-refund-tool' \
  -d '{
    "workspace_id": "wsp_01JAV…",
    "environment_id": "env_01JAV…",
    "key": "refund_customer",
    "name": "Refund a customer order",
    "description": "Issues a refund against an order in the payments service.",
    "kind": "HTTP",
    "required_capability": "refund.create",
    "endpoint_url": "https://payments.internal.example.com/refunds",
    "http_method": "POST",
    "destination_allowlist": ["payments.internal.example.com"],
    "credential_id": "cred_01JAV…",
    "risk_level": "HIGH",
    "dangerous": true,
    "sensitive_parameters": ["customer.email", "customer.phone"],
    "parameter_schema": {
      "type": "object",
      "required": ["orderId", "reason"],
      "properties": {
        "orderId": { "type": "string" },
        "reason": { "type": "string", "maxLength": 500 }
      }
    }
  }'
workspace_idstringrequired

Which workspace owns the tool.

environment_idstringoptional

Scope it to one environment. null makes it available across the workspace's environments. Scope production tools to production.

keystringrequired

What the agent passes as tool. Stable; policy rules reference it.

kindenumrequired

HTTP CLIENT MCP A2A DATABASE WEBHOOK SIMULATED. Only HTTP performs real egress. See HTTP or CLIENT.

required_capabilitystringrequired

The capability an agent must hold. Note the field name — it is required_capability, not capability.

endpoint_urlstringoptional

Required for HTTP. Must be HTTPS unless the host is loopback.

http_methodenumoptional

GET POST PUT PATCH DELETE. Defaults to POST.

destination_allowliststring[]optional

Hosts this tool may contact. Checked again at the egress boundary.

credential_idstringoptional

The credential the broker leases for this tool. Omit and the tool runs unauthenticated downstream.

risk_levelenumoptional

LOW MEDIUM HIGH CRITICAL. A policy field: tool.risk_level.

dangerousbooleanoptional

Marks the tool destructive or high impact. A policy field: tool.dangerous. Templates use it to require approval, and doctor flags a dangerous tool with no rule covering it.

sensitive_parametersstring[]optional

Dotted paths redacted from logs, audit and the stored result summary.

parameter_schemaobjectoptional

JSON Schema. Validated before execution, so a malformed call fails at the gateway rather than downstream.

#HTTP or CLIENT

Both kinds go through the same pipeline: authentication, capability, policy, risk, approval and audit. They differ in who performs the call once it is permitted.

HTTP CLIENT
Performs the call The gateway Your code, inside guard()
Holds the credential The broker; the agent never sees it Your code
endpoint_url, credential_id Required for real egress Not allowed
Bypassable by skipping the SDK No, there is nothing to call with Yes
Registered by veefore init No Yes

CLIENT is how an existing agent gets decisions, approvals and an audit trail on day one without moving any secrets. HTTP is where you end up for tools that matter: broker the credential, re-register the tool as HTTP with its endpoint, and guard() starts returning the gateway's result instead of running your function. Nothing executes twice, and no code changes.

bash
curl -X POST https://veefore.example.com/v1/tools \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -d '{
    "workspace_id": "wsp_01JAV…",
    "key": "lookup_order",
    "name": "Look up an order",
    "kind": "CLIENT",
    "required_capability": "tool.lookup_order",
    "destination_allowlist": ["api.shop.example.com"],
    "risk_level": "LOW"
  }'

#Registering grants nothing

bash
curl -X POST https://veefore.example.com/v1/tools/tool_01ABC/agents \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -d '{
    "agent_id": "agt_01JAV…",
    "parameter_restrictions": { "orderId": { "pattern": "^ord_" } }
  }'

Two steps, deliberately

If holding refund.create automatically granted access to every tool declaring it, then registering a new refund tool would silently widen what every existing finance agent could reach. Tool registration would be a privilege escalation.

With the steps separated, registration grants nobody anything. The two refusals are distinct so you can tell which half is missing: CAPABILITY_NOT_GRANTED versus TOOL_NOT_AUTHORIZED.

parameter_restrictions narrows further, per agent. The same tool can be restricted differently for different agents without a policy rule.

Revoke with DELETE /v1/tools/{toolId}/agents/{agentId}.

#Egress guards

When GATEWAY_ALLOW_REAL_EGRESS=true and the tool kind is HTTP, the gateway makes a real outbound call. Six guards apply at the egress boundary — after policy, after approval, after the credential is leased, immediately before bytes leave the process:

Guard Refusal
Tool kind must be HTTP Otherwise the simulated runtime runs
endpoint_url must be set UNPROCESSABLE
Host must be in the tool's own destination_allowlist DESTINATION_BLOCKED
HTTPS required unless loopback DESTINATION_BLOCKED
redirect: 'error' — redirects are never followed Execution fails
Timeout at GATEWAY_EGRESS_TIMEOUT_MS (15s) EXECUTION_TIMEOUT

Plus a circuit breaker per tool: five consecutive failures opens it for 20 seconds, so one broken downstream cannot consume the gateway's capacity.

Redirects are refused, not followed

A 302 from your downstream fails the execution. This is deliberate: following a redirect is how an allowlisted host becomes a request to a host that was never allowlisted, which is server-side request forgery with extra steps.

If your downstream redirects, point endpoint_url at the final location.

Headers the gateway always sends:

http
content-type: application/json
accept: application/json
user-agent: Veefore-Gateway/1.0
x-veefore-request-id: req_01JAV…
x-veefore-agent-id: agt_01JAV…
idempotency-key: …            # when the agent supplied one

Plus trace propagation headers, plus whatever the leased credential contributes. x-veefore-request-id is worth logging on your side — it ties your downstream log line to the Veefore action record.

#Without real egress

With GATEWAY_ALLOW_REAL_EGRESS=false — the default — or for kind SIMULATED, the simulated runtime handles execution. It produces deterministic responses so the full pipeline can be exercised end to end, and every response carries simulated: true. Nothing is ever presented as output from a real system when it is not.

That flag defaults to off so a local run cannot reach a real external system by accident. Turn it on deliberately. See Local development.

#Disable one

bash
curl -X POST https://veefore.example.com/v1/tools/tool_01ABC/disable \
  -H "Authorization: Bearer $VEEFORE_API_KEY" \
  -H 'content-type: application/json' \
  -d '{ "reason": "Payments service maintenance window" }'

Immediate, for every agent. Refused with TOOL_DISABLED — which is distinct from a policy BLOCK, so the agent's logs say what actually happened.

Statuses: ACTIVE, RESTRICTED, DISABLED.

#What policy can see

Field Type
tool.id string
tool.key string
tool.kind HTTP CLIENT MCP A2A DATABASE WEBHOOK SIMULATED
tool.protocol HTTP MCP A2A
tool.risk_level LOW MEDIUM HIGH CRITICAL
tool.dangerous boolean
destination.host string
destination.risk_level LOW MEDIUM HIGH CRITICAL

tool.dangerous is the one worth using. Mark destructive tools and let the starter policy require approval for all of them at once, rather than enumerating tool keys in a rule that goes stale.

#Practical advice

Set dangerous: true generously. The cost is an approval step. The cost of not setting it is an agent doing something irreversible with nobody notified.

Keep destination_allowlist as narrow as the tool needs. One host is typical. It is checked twice — in the pipeline and at egress — and the second check is what protects you if the endpoint is later edited.

Fill in sensitive_parameters. Redaction is applied on the way in, so a listed path never reaches logs or audit at all. There is no code path where it is written and later filtered.

Use parameter_schema. A malformed call failing at the gateway with VALIDATION_FAILED is much easier to debug than a 500 from your downstream.

Identity, authority, policy and enforcement for autonomous AI agents.