Skip to main content
Some fields only make sense in certain contexts. Requiring an email address when the user chose SMS delivery is noise; omitting a phone number when they chose SMS is a bug. A discriminated union encodes this cleanly: one branch for email, one branch for SMS.

Use case

A checkout flow where delivery_method decides which contact details are mandatory. When the user wants email delivery, you need their email address. When they want SMS, you need their phone number. Both should never be required simultaneously.

Schema pattern

{
  "anyOf": [
    {
      "type": "object",
      "properties": {
        "delivery_method": { "type": "string", "const": "email" },
        "email": { "type": "string", "pattern": "^[^@]+@[^@]+$" }
      },
      "required": ["delivery_method", "email"],
      "additionalProperties": false
    },
    {
      "type": "object",
      "properties": {
        "delivery_method": { "type": "string", "const": "sms" },
        "phone": { "type": "string", "pattern": "^\\+?[1-9][0-9]{7,14}$" }
      },
      "required": ["delivery_method", "phone"],
      "additionalProperties": false
    }
  ]
}

Prompt snippet

Infer the delivery method from the user request.
If method is email, include email.
If method is sms, include phone in international format.

Example outputs

{
  "delivery_method": "email",
  "email": "jane@acme.com"
}
{
  "delivery_method": "sms",
  "phone": "+14155551234"
}

Why this works

The anyOf branches split the payload into two exact shapes. The email branch requires email, and the SMS branch requires phone. Because delivery_method is fixed with const in each branch, the model cannot mix fields across branches, so anyOf is equivalent to oneOf here.