Tool Discovery.
Discover available API operations as machine-readable tool definitions.
The /tools endpoint lets your agent discover what it can do. It returns machine-readable tool definitions scoped to the authenticated key's role and permissions — no manual tool configuration required.
How It Works
sequenceDiagram
participant Agent as Your Agent
participant API as Agent API
Note over Agent: 1. Agent starts up
Agent->>API: GET /api/agent/v1/tools?format=openai
Note over API: Reads agent-api.json<br/>Filters by key's role<br/>Filters by key's scopes<br/>Filters by permissions<br/>Formats for framework
API-->>Agent: Tool definitions (JSON)
Note over Agent: 2. Passes tools to LLM provider
Agent->>API: POST, GET, PUT... (tool calls)
Note over Agent: 3. LLM calls tools →<br/>Agent routes to Agent API
API-->>Agent: API responses
Your agent calls /tools once at startup, then uses the returned definitions for all subsequent LLM interactions.
Request
curl -X GET https://your-domain.com/api/agent/v1/tools?format=openai \
-H "X-Agent-Key: rl_agent_..."
| Parameter | Type | Default | Description |
|---|---|---|---|
format |
string | generic |
Output format: openai, anthropic, mcp, or generic |
Response
{
"error": false,
"tools": [ ... ],
"meta": {
"role": "partner",
"format": "openai",
"tool_count": 46,
"cached": false
}
}
The meta section includes how many tools are available and whether this response was served from cache.
Supported Formats
OpenAI Function Calling (?format=openai)
Returns tools in the OpenAI function calling format. Each tool is a type: "function" object with name, description, and parameters schema.
[
{
"type": "function",
"function": {
"name": "list_loyalty_cards",
"description": "List all loyalty cards for this partner\n...\n\nHTTP: GET /api/agent/v1/partner/cards",
"parameters": {
"type": "object",
"properties": {
"page": { "type": "integer", "default": 1 },
"per_page": { "type": "integer", "default": 25 }
},
"required": []
}
}
}
]
Anthropic/Claude Tool Use (?format=anthropic)
Returns tools in the Anthropic tool use format. Each tool has name, description, and input_schema.
[
{
"name": "record_purchase",
"description": "Record a purchase and award loyalty points\n...\n\nHTTP: POST /api/agent/v1/partner/transactions/purchase",
"input_schema": {
"type": "object",
"properties": { ... },
"required": ["card_id", "member_identifier", "purchase_amount"]
}
}
]
MCP (?format=mcp)
Returns tools in the Model Context Protocol format. Wrapped in a { "tools": [...] } envelope with inputSchema for each tool.
Generic JSON Schema (?format=generic)
Returns a self-documenting format with method, path, scopes, and full parameter schemas as first-class fields. Suitable for custom integrations, Zapier/Make/n8n, and any platform that can consume JSON.
{
"api_name": "Reward Loyalty Agent API",
"api_version": "1.0.0",
"base_url": "/api/agent/v1",
"auth": {
"type": "api_key",
"header": "X-Agent-Key"
},
"tools": [
{
"name": "list_loyalty_cards",
"description": "List all loyalty cards for this partner",
"method": "GET",
"path": "/api/agent/v1/partner/cards",
"required_scopes": ["read", "write:cards"],
"parameters": { ... }
}
]
}
Schema Preservation
Tool parameters preserve the full JSON Schema structure from the OpenAPI spec. This includes:
- Translatable fields —
oneOf: [string, object]for fields that accept either a plain string or a locale-keyed object ({"en": "...", "nl": "..."}) - Nested objects — object-typed properties with their own sub-properties
- Arrays — array-typed properties with
itemsschema - Enums, patterns, min/max, format — all JSON Schema keywords pass through
This means your LLM receives accurate type information for every parameter, including complex types.
Role, Scope & Permission Filtering
The /tools endpoint only returns tools the authenticated key can actually use. Three layers of filtering are applied:
Role Filtering
- Partner keys see partner endpoints + health (up to 46 tools)
- Admin keys see admin endpoints + health (up to 10 tools)
- Member keys see member endpoints + health (up to 14 tools)
Scope Filtering
- Keys with limited scopes (e.g.,
readonly) see only the endpoints their scopes grant access to - Keys with the
adminsuper-scope see all endpoints for their role
Permission Filtering (Partner Only)
Partner keys are subject to two layers of permission checks:
Top-level API access — If agent_api_permission is false for the partner, /tools returns 403 FEATURE_DISABLED immediately. No tools are returned. This is the same response the partner would receive from any partner endpoint.
{
"error": true,
"code": "FEATURE_DISABLED",
"message": "Agent API access has been revoked for this partner.",
"retry_strategy": "contact_support",
"details": { "permission": "agent_api_permission" }
}
Sub-feature filtering — If the partner has API access but individual features are disabled, the gated endpoints are excluded from the tool list — because calling them would return 403 FEATURE_DISABLED:
| Feature Permission | Endpoints Hidden When Disabled |
|---|---|
loyalty_cards_permission |
All loyalty card and reward CRUD (10 endpoints) |
stamp_cards_permission |
All stamp card CRUD + stamp/redeem operations (7 endpoints) |
vouchers_permission |
All voucher CRUD + validate/redeem operations (7 endpoints) |
This means two partner keys with the same scopes but different plans may see different tool sets.
The /tools endpoint itself is excluded from the tool list — a tool that lists tools is meta-noise for agents.
CLI Export
You can also export tool definitions via the command line:
# Default: generic format, partner role
php artisan agent:export-tools
# OpenAI format for admin endpoints
php artisan agent:export-tools openai --role=admin
# Claude format for member endpoints
php artisan agent:export-tools anthropic --role=member
# Read-only partner tools
php artisan agent:export-tools generic --role=partner --scopes=read
Output is saved to storage/api-docs/agent-tools-{format}.json.
Caching
Tool definitions are cached for 24 hours per unique combination of spec version, key role, scopes, feature permissions, and format. The cache is automatically invalidated when:
- The OpenAPI spec is regenerated (spec version/filemtime changes)
- A different combination of role + scopes + permissions is requested
No manual cache:clear is needed.
Error Responses
| Status | Code | Meaning |
|---|---|---|
| 403 | FEATURE_DISABLED |
Partner's Agent API access has been revoked (agent_api_permission = false). |
| 422 | INVALID_FORMAT |
Unsupported format parameter. Use: openai, anthropic, mcp, or generic. |
| 503 | TOOLS_UNAVAILABLE |
The OpenAPI spec has not been generated yet. Run php artisan l5-swagger:generate agent. |
Integration Example
Here's a complete integration with OpenAI:
import openai, requests, json
AGENT_KEY = "rl_agent_..."
BASE_URL = "https://your-domain.com"
# 1. Discover tools (once at startup)
resp = requests.get(
f"{BASE_URL}/api/agent/v1/tools?format=openai",
headers={"X-Agent-Key": AGENT_KEY}
)
tools = resp.json()["tools"]
# 2. Pass to OpenAI
response = openai.chat.completions.create(
model="gpt-4",
messages=[{"role": "user", "content": "Award 50 points to [email protected]"}],
tools=tools,
)
# 3. Execute the tool call
tool_call = response.choices[0].message.tool_calls[0]
fn = tool_call.function
desc = next(t["function"]["description"] for t in tools if t["function"]["name"] == fn.name)
http_line = [l for l in desc.split("\n") if l.startswith("HTTP:")][0]
method, path = http_line.replace("HTTP: ", "").split(" ", 1)
result = requests.request(
method=method,
url=f"{BASE_URL}{path}",
headers={"X-Agent-Key": AGENT_KEY},
json=json.loads(fn.arguments),
)
print(result.json())
Related Topics
- OpenAPI 3.0 Spec — Interactive Swagger UI for the Agent API (raw JSON)
- Endpoint Reference — Every endpoint across all roles in one page
- Scopes & Permissions — Permission levels and what each scope unlocks
- Authentication — How keys work, security model, and error handling