tool_schema = {
"name": "create_support_ticket",
"description": "Creates a support ticket for a customer issue.",
"input_schema": {
"type": "object",
"properties": {
# String with format constraint
"customer_id": {
"type": "string",
"description": "Customer identifier in format 'C-XXXXXX'. "
"Obtain from get_customer result.",
"pattern": "^C-[0-9]{6}$" # Regex validation
},
# Enum — constrained to valid values
"category": {
"type": "string",
"enum": ["billing", "shipping", "product_defect", "account_access", "other"],
"description": "Issue category. Use 'other' only if none of the specific "
"categories apply."
},
# Enum with description of each value
"priority": {
"type": "string",
"enum": ["low", "medium", "high", "urgent"],
"description": "Ticket priority. "
"urgent: customer cannot use product at all. "
"high: significant functionality impaired. "
"medium: partial functionality affected. "
"low: cosmetic or minor issue.",
"default": "medium"
},
# String with length constraints
"description": {
"type": "string",
"description": "Detailed description of the issue in the customer's words. "
"Include: what they were trying to do, what happened instead, "
"any error messages. Minimum 50 characters.",
"minLength": 50,
"maxLength": 2000
},
# Optional array
"related_order_ids": {
"type": "array",
"items": {
"type": "string",
"pattern": "^ORD-[0-9]{8}$"
},
"description": "Order IDs related to this issue (format: 'ORD-XXXXXXXX'). "
"Optional — include only if this issue is order-specific.",
"maxItems": 5
}
},
"required": ["customer_id", "category", "priority", "description"]
# related_order_ids is NOT required — it's genuinely optional
}
}
When to Use Each Schema Type
| Situation | Use |
|---|
| Fixed set of valid values | enum |
| Free text with format rules | string with pattern |
| Numeric with range | integer or number with minimum/maximum |
| Yes/no decision | boolean |
| Collection of items | array with items schema |
| Grouped related fields | object with nested properties |
The Required vs Optional Decision
Only mark fields as required if Claude can always provide them for any valid call.
# ❌ Wrong: making conditional fields required
"required": ["customer_id", "order_id", "payment_id"]
# What if the issue isn't order or payment related?
# ✅ Right: only require what's always available
"required": ["customer_id", "category", "description"]
# order_id and payment_id are optional — included when relevant
Key Takeaways
- enum for fields with fixed valid values — prevents invalid inputs
- required only for fields Claude can always provide
- Descriptions on every parameter — not just the top-level schema
- Pattern constraints for formatted strings (IDs, dates, codes)
- Default values for optional fields with common defaults