Skip to main content
Some fields only make sense together. A VAT ID without a billing country is useless because you can’t validate it, route it, or report on it. A shipping tracking number without a carrier name is just a random string. dependentRequired encodes these relationships directly in the schema: if field A appears, fields B and C must also appear. This is simpler than if/then because it doesn’t depend on a field’s value, only its presence. It’s the right tool when fields travel in groups.

Use case

Customer billing details where vat_id, company_name, and billing_country must all appear together. If the customer is a business with a VAT ID, you need the other two fields to validate and process it.

Schema pattern

JSON Schema
{
  "type": "object",
  "properties": {
    "customer_type": { "type": "string", "enum": ["individual", "business"] },
    "company_name": { "type": "string", "minLength": 1, "maxLength": 120 },
    "vat_id": { "type": "string", "pattern": "^[A-Z0-9-]{6,20}$" },
    "billing_country": { "type": "string", "pattern": "^[A-Z]{2}$" }
  },
  "required": ["customer_type"],
  "dependentRequired": {
    "vat_id": ["company_name", "billing_country"]
  },
  "additionalProperties": false
}
Pydantic and Zod can validate the same rule in application code, but they do not emit dependentRequired in the generated JSON Schema. For structured generation, prefer raw JSON Schema whenever this dependency needs to be part of the contract you send to the model.
curl
curl https://api.dottxt.ai/v1/chat/completions \
  -H "Authorization: Bearer $DOTTXT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-oss-20b",
    "messages": [{ "role": "user", "content": "Business customer: Acme Logistics, VAT ID FR-12345678, billing country France (FR)." }],
    "response_format": {
      "type": "json_schema",
      "json_schema": {
        "name": "billing_details",
        "schema": {
          "type": "object",
          "properties": {
            "customer_type": { "type": "string", "enum": ["individual", "business"] },
            "company_name": { "type": "string", "minLength": 1, "maxLength": 120 },
            "vat_id": { "type": "string", "pattern": "^[A-Z0-9-]{6,20}$" },
            "billing_country": { "type": "string", "pattern": "^[A-Z]{2}$" }
          },
          "required": ["customer_type"],
          "dependentRequired": {
            "vat_id": ["company_name", "billing_country"]
          },
          "additionalProperties": false
        }
      }
    }
  }'

Example outputs

Valid business record:
{
  "customer_type": "business",
  "company_name": "Acme Logistics",
  "vat_id": "FR-12345678",
  "billing_country": "FR"
}
Invalid pattern to avoid (missing dependency):
{
  "customer_type": "business",
  "vat_id": "FR-12345678"
}

Why this works

Without dependentRequired, the model might produce {"customer_type": "business", "vat_id": "FR-12345678"}: a business record with a VAT ID but no company name or billing country. Your application would then need to either reject the record and retry, or patch the missing fields from another source. Both options are expensive. dependentRequired prevents this at generation time. The model sees the constraint and produces all related fields together, or none of them. This keeps your application code simple: you validate once and process, rather than validate-then-repair. If this dependency needs to be part of the generated schema contract, use raw JSON Schema in response_format. Use the Pydantic and Zod patterns only when you are validating after generation inside your own application.