JSON Schema for Tool Parameters: A Reference Guide
Tool parameters are almost always a JSON Schema object describing one JSON object of arguments.
Search across all documentation pages
Tool parameters are almost always a JSON Schema object describing one JSON object of arguments.
Providers differ on which keywords they honor strictly. This cheatsheet covers the conventions that work well for agent tools across OpenAI-compatible APIs, OpenRouter, and common frameworks (verify vendor support at build).
{
"type": "object",
"properties": {
"order_id": {
"type": "integer",
"description": "Numeric order id, e.g. 1042"
}
},
"required": ["order_id"],
"additionalProperties": false
}| Field | Role |
|---|---|
type: "object" | Root arguments are always an object for tools |
properties | Named parameters |
required | Must-present keys |
additionalProperties: false | Reject surprise keys (support varies; enforce in host) |
per-property description | Steers argument fill quality |
| JSON Schema type | Use for | Notes |
|---|---|---|
string | Names, ids-as-text, free text | Add enum, pattern, or format notes in description |
integer | Counts, numeric ids | Models sometimes emit strings; coerce carefully in host |
number | Floats, money if not integer cents | Prefer integer cents for currency |
boolean | Flags | Avoid tri-state; use optional bool or enum |
null | Rare | Many tool stacks dislike nullable unions; prefer omit optional |
{
"email": {
"type": "string",
"description": "Customer email, e.g. ada@example.com"
},
"limit": {
"type": "integer",
"description": "Page size",
"minimum": 1,
"maximum": 100
},
"dry_run": {
"type": "boolean",
"description": "If true, validate only and do not commit"
}
}{
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"description": "Temperature unit"
}
}| Guidance | Why |
|---|---|
| Keep enums small | Large enums bloat tokens and confuse selection |
| Use stable wire values | Display labels belong in descriptions, not alternate enum spellings |
| Prefer enum over free string | Cuts invented synonyms (C, celcius) |
{
"type": "object",
"properties": {
"item_ids": {
"type": "array",
"description": "Product ids to include",
"items": { "type": "string" },
"minItems": 1,
"maxItems": 20
},
"address": {
"type": "object",
"description": "Shipping address",
"properties": {
"line1": { "type": "string" },
"city": { "type": "string" },
"country": {
"type": "string",
"description": "ISO 3166-1 alpha-2, e.g. PT"
}
},
"required": ["line1", "city", "country"],
"additionalProperties": false
}
},
"required": ["item_ids"],
"additionalProperties": false
}| Pattern | Prefer when |
|---|---|
| Flat parameters | Simple tools; easier for models |
| One nested object | Natural record (address, money amount+currency) |
| Deep trees | Avoid; split tools or accept host-side assembly |
| Approach | Schema | Host behavior |
|---|---|---|
| Required | list key in required | Reject if missing |
| Optional omit | not in required | Apply default in code |
| Optional with default keyword | "default": 5 | Helpful docs; still default in host |
| Sentinel empty string | discouraged | Prefer omit or null policy you document |
Do not list a key as required if the model rarely has the value. Inject server-side context (tenant, actor id) in the host instead of asking the model to guess.
| Keyword | Example | Caveat |
|---|---|---|
minimum / maximum | integers, numbers | Enforce in host too |
minLength / maxLength | strings | Good guard against dumps |
minItems / maxItems | arrays | Cap blast radius |
pattern | "^[A-Z]{2}$" | Models may still fail; return clear errors |
format | date-time, email | Support varies widely |
{
"sku": {
"type": "string",
"description": "SKU like ABC-1234",
"pattern": "^[A-Z]{3}-[0-9]{4}$"
},
"ship_by": {
"type": "string",
"description": "ISO-8601 date (YYYY-MM-DD), UTC calendar date"
}
}{
"identifier": {
"description": "Order id as int or external string key",
"anyOf": [
{ "type": "integer" },
{ "type": "string", "minLength": 1 }
]
}
}| Advice | Reason |
|---|---|
| Prefer two tools or one clear type | Unions increase invalid args |
| If you must union, document decision rule | "Use int when numeric; else external key" |
| Validate host-side exhaustively | Model-produced unions are messy |
Many OpenAI-compatible APIs wrap the schema:
tool = {
"type": "function",
"function": {
"name": "get_order_status",
"description": "Fetch live status for one order id.",
"parameters": {
"type": "object",
"properties": {
"order_id": {"type": "integer", "description": "e.g. 1042"}
},
"required": ["order_id"],
"additionalProperties": False,
},
},
}Other stacks (Anthropic-style tool specs, MCP inputSchema, Pydantic AI, LangGraph) carry the same object schema under slightly different keys.
Keep an internal canonical schema and adapt at the edge.
from pydantic import BaseModel, Field
class GetOrderArgs(BaseModel):
order_id: int = Field(description="Numeric order id, e.g. 1042")
model_config = {"extra": "forbid"}
schema = GetOrderArgs.model_json_schema()
# use schema as the tool parameters object; verify $defs inlining for your provider| Benefit | Watch-out |
|---|---|
| Single source for validate + schema | Some exporters emit $refs providers dislike |
| Field descriptions stay close to code | Still write tool-level description separately |
| Check | On failure |
|---|---|
| JSON parse of arguments string | tool error invalid_json |
| Schema validate | tool error with path + expected type |
| Business rules | tool error invalid_argument with fix hint |
| Authz | tool error or hard refuse without leaking secrets |
| Size caps | truncate or reject oversized strings/arrays |
No universal guarantee. Stick to a conservative subset: object, properties, required, type, enum, basic numeric/string bounds. Verify at build for each model/provider.
Yes when the provider honors it, and always enforce in host validation. Surprise keys are a common model failure mode.
Use the type your backend truly uses. If systems are mixed, document one preferred type and normalize in the host.
Prefer integer minor units (amount_cents) plus a currency enum. Floating number invites rounding bugs.
Yes for no-arg tools: "properties": {} with "required": []. Some APIs still want type: object.
Tool parameters are inputs. Output shape is your observation contract; some platforms also support structured final answers separately.
Weak description, overloaded context, or model limits. Return a clear error and tighten the schema/description; consider forcing the tool only when appropriate.
Often problematic for tool calling. Inline small nested objects unless your provider documents $ref support.
Stack versions: Pins from the category manifest (verify at build): OpenRouter (~315+ models, July 2026 pricing/fees); LangGraph 1.0+; CrewAI 1.14+; Microsoft Agent Framework 1.0; Vercel AI SDK 6; Pydantic AI (latest); LlamaIndex (latest); OpenAI Agents SDK (latest + MCP); MCP (Linux Foundation governance); A2A (HTTP+SSE+JSON-RPC 2.0); Solana
@solana/web3.js+@solana/spl-token.
Reviewed by Chris St. John·Last updated Jul 16, 2026