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, so you skip manual tool configuration.
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 |
pass_format |
integer | 1 |
1 keeps visit-pass tools and shapes; 2 includes typed monetary contracts allowed by the key |
Response
Schematic JSON (omitted fields use ...):
{
"error": false,
"tools": [ ... ],
"meta": {
"role": "partner",
"format": "openai",
"tool_count": 46,
"cached": false
}
}
The meta section includes how many tools are available and whether the response came 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.
Schematic JSON (omitted fields use ...):
[
{
"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. The response's tools field contains a { "tools": [...] } object with inputSchema for each tool. Read the definitions at response.tools.tools.
Generic JSON schema (?format=generic)
The example below shows the contents of the response's tools field. This format has its own tools array, so read definitions at response.tools.tools.
Returns a self-documenting format with method, path, scopes, and full parameter schemas as first-class fields. Suitable for Zapier, Make, n8n, and any platform that can consume JSON.
Schematic JSON (omitted fields use ...):
{
"api_name": "Reward Loyalty Agent API",
"api_version": "1.1.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 returns tools the authenticated key can use, nothing more. Three filtering layers apply:
Role filtering
- Partner keys see partner endpoints and the health check
- Admin keys see admin endpoints and the health check
- Member keys see member endpoints and the health check
Scope filtering
- Keys with limited scopes (e.g.,
read) see the endpoints their scopes grant access to, nothing more - Keys with the
adminsuper-scope see ordinary endpoints for their role. Monetary write tools also requirepass_format=2and both literal scopes,write:passesandwrite:pass-money.
Permission filtering (partner)
Partner keys pass two layers of permission checks:
Top-level API access. If agent_api_permission is false for the partner, /tools returns 403 FEATURE_DISABLED. The response matches what 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 platform excludes the gated endpoints from the tool list. Calling them would return 403 FEATURE_DISABLED:
| Feature Permission | Endpoints Hidden When Disabled |
|---|---|
loyalty_cards_permission |
All loyalty card and reward CRUD |
stamp_cards_permission |
All stamp card CRUD and stamp/redeem operations |
vouchers_permission |
All voucher CRUD and validate/redeem operations |
prepaid_passes_permission |
Visit-pass CRUD and sell/scan/undo operations; monetary reads and existing-value servicing use separate checks |
Two partner keys with the same scopes but different plans may see different tool sets. Format 2 keeps authorized monetary reads available when new pass sales are disabled. Each write still checks current authority and the rules for servicing existing paid balances.
The /tools endpoint does not appear in its own tool list. A tool that lists tools adds 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 partner tools (no writes)
php artisan agent:export-tools generic --role=partner --scopes=read
# Opt in to typed monetary tools with both explicit write grants
php artisan agent:export-tools generic --role=partner --pass-format=2 --scopes=read,write:passes,write:pass-money
The command saves output to storage/api-docs/agent-tools-{format}.json. It defaults to --pass-format=1; exporting a format 2 schema does not grant a runtime key any scope.
For monetary calls, put pass_format=2 in the URL query and Idempotency-Key in the HTTP headers. Generic discovery lists the header separately; framework tool schemas label it as an HTTP header. Your adapter must move it into the header, not send it in the JSON body.
Caching
The platform caches tool definitions for 24 hours per unique combination of spec version, key role, scopes, feature permissions, output format, and pass format. The cache invalidates when:
- You regenerate the OpenAPI spec (spec version/filemtime changes)
- A request uses a different combination of role + scopes + permissions
You never need a manual cache:clear.
Error responses
| Status | Code | Meaning |
|---|---|---|
| 403 | FEATURE_DISABLED |
An admin revoked the partner's Agent API access (agent_api_permission = false). |
| 422 | INVALID_FORMAT |
Unsupported format parameter. Use: openai, anthropic, mcp, or generic. |
| 422 | INVALID_PASS_FORMAT |
Unsupported or empty pass format. Use 1 or 2. |
| 503 | TOOLS_UNAVAILABLE |
The OpenAPI spec does not exist yet. Run php artisan l5-swagger:generate agent. |
Integration example
This example fetches tool definitions for a provider integration. It does not execute model-selected operations.
import os
import requests
response = requests.get(
"https://your-domain.com/api/agent/v1/tools",
params={"format": "openai"},
headers={"X-Agent-Key": os.environ["REWARD_LOYALTY_AGENT_KEY"]},
timeout=30,
)
response.raise_for_status()
tool_definitions = response.json()["tools"]
Before executing a tool call, validate its name and arguments against the discovered schema. Bind and URL-encode path variables such as {id}. Send GET filters as query parameters and write fields as JSON. Handle responses with no tool call, and apply the retry rules before repeating writes. A purchase also needs the target card and member, not just a points amount.
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