{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "$id": "https://artifacts.apis.io/corebee-ai/json-schema/corebee-ai-bridge-voice-settings-schema.json",
  "title": "BridgeVoiceSettings",
  "x-generated": "2026-11-04",
  "x-method": "derived",
  "x-generator": "derive-json-schema.py",
  "x-source": "openapi/corebee-ai-openapi.yml#/components/schemas/BridgeVoiceSettings",
  "type": "object",
  "required": [
    "default_voice_id",
    "org_default_enabled",
    "using_platform_default",
    "effective_default_voice_id",
    "numbers_overriding",
    "warnings"
  ],
  "properties": {
    "default_voice_id": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
      "description": "Your stored org default voice, or null."
    },
    "default_voice": {
      "oneOf": [
        {
          "$ref": "#/$defs/BridgeVoice"
        },
        {
          "type": "null"
        }
      ],
      "description": "The stored default as a full voice record (curated is false when it is not on the recommended list). null when no default is stored, or when the details of a voice off the recommended list could not be fetched just now (warning voice_details_unavailable says why); default_voice_id is still correct."
    },
    "org_default_enabled": {
      "type": "boolean",
      "description": "Whether a stored default is applied to calls: our server switch, and a per-organization switch we can turn off without a deploy. While false a stored default is kept but NOT applied to calls (warning org_default_disabled says which)."
    },
    "using_platform_default": {
      "type": "boolean",
      "description": "True when numbers without their own voice speak in the platform default voice."
    },
    "effective_default_voice_id": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
      "description": "The voice a number with no voice of its own will be served on its next call, or null for the platform default."
    },
    "platform_default_voice_id": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
    },
    "previous_default_voice_id": {
      "type": [
        "string",
        "null"
      ],
      "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
      "description": "The value the last change replaced, for a one-step undo."
    },
    "updated_at": {
      "type": [
        "string",
        "null"
      ],
      "format": "date-time",
      "description": "When the default was last changed, through this API or by our daily re-check (see auto_cleared). Send it back on PATCH (or as If-Match) to have a stale write refused with 409 instead of overwriting a newer change."
    },
    "auto_cleared": {
      "oneOf": [
        {
          "type": "object",
          "required": [
            "voice_id",
            "reason",
            "at"
          ],
          "properties": {
            "voice_id": {
              "type": "string",
              "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$",
              "description": "The default we cleared (also in previous_default_voice_id)."
            },
            "reason": {
              "type": "string",
              "description": "Why, as a short code: voice_not_found, voice_not_active, voice_not_visible, or synthesis_rejected:<code> when the voice failed the test line, where <code> is one of voice_unsupported (the voice cannot be spoken on the voice model our calls use), language_unsupported, voice_not_found or voice_refused (any other refusal). BEHAVIOUR CHANGE (2026-10-23): <code> used to be served as recorded; it is now mapped: voice_model_mismatch, voice_not_supported, model_not_supported and model_not_found become voice_unsupported; language_not_supported becomes language_unsupported; voice_not_found stays; anything else becomes voice_refused. The same codes appear in the org_default_auto_cleared warning and the 400 voice_not_available message. Update any exact string match."
            },
            "at": {
              "type": "string",
              "format": "date-time"
            }
          }
        },
        {
          "type": "null"
        }
      ],
      "description": "Set when our daily re-check found that the voice library definitely no longer accepts the org default (deleted, archived, no longer available to us, or it failed the test line), so we set the default back to null and calls use the platform default: a call in that voice would have had no agent audio. A warning org_default_auto_cleared says the same while no new default is set. null otherwise, and dropped by your next PATCH that changes default_voice_id. An outage never clears anything."
    },
    "numbers_overriding": {
      "type": "array",
      "description": "Numbers that have their own voice and therefore do NOT use the org default. At most 200, ordered by number (see numbers_overriding_truncated).",
      "items": {
        "type": "object",
        "properties": {
          "from_number": {
            "type": "string"
          },
          "voice_id": {
            "type": "string",
            "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
          }
        }
      }
    },
    "numbers_overriding_truncated": {
      "type": "boolean",
      "description": "True when more than 200 numbers have their own voice: numbers_overriding lists the first 200 by number (warning numbers_truncated); page through GET /voice/bridge/numbers for all."
    },
    "explanation": {
      "type": "string",
      "description": "One sentence: which voice the next call uses and why."
    },
    "warnings": {
      "type": "array",
      "description": "Non-fatal notes about this response. Empty on the common path. Same {path, code, message} shape as /voice/bridge/numbers/instructions. Tolerated and ignored if you send it back.",
      "items": {
        "$ref": "#/$defs/BridgeVoiceWarning"
      }
    },
    "speech": {
      "type": "object",
      "description": "The stored speech settings (null = not set here). Present only once something is stored, or when the request sent `speech`. A stored value that is not switched on yet is kept but not applied to calls (on the settings endpoint, warning speech_not_applied says which).",
      "properties": {
        "speed": {
          "type": [
            "number",
            "null"
          ]
        },
        "volume": {
          "type": [
            "number",
            "null"
          ]
        },
        "language": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "en",
            "es",
            null
          ]
        }
      }
    }
  },
  "$defs": {
    "BridgeVoice": {
      "type": "object",
      "required": [
        "voice_id",
        "name",
        "curated",
        "preview_url",
        "preview_requires_auth"
      ],
      "properties": {
        "voice_id": {
          "type": "string",
          "pattern": "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"
        },
        "name": {
          "type": "string"
        },
        "description": {
          "type": "string"
        },
        "gender": {
          "type": [
            "string",
            "null"
          ],
          "enum": [
            "feminine",
            "masculine",
            "gender_neutral",
            null
          ],
          "description": "How the voice presents, in our own labels. null when the voice library does not say."
        },
        "accent": {
          "type": [
            "string",
            "null"
          ],
          "description": "Slug for the voice's native accent."
        },
        "locale": {
          "type": [
            "string",
            "null"
          ],
          "description": "BCP-47 locale of the native accent."
        },
        "curated": {
          "type": "boolean",
          "description": "On our recommended list: each voice was rendered once with a real AskOtto greeting on the voice model our calls use. Not test-called over the phone; place one test call before relying on any voice."
        },
        "recommended_for": {
          "type": [
            "string",
            "null"
          ],
          "description": "Our note on where a curated voice fits; null for other voices."
        },
        "is_platform_default": {
          "type": "boolean",
          "description": "The platform default voice as of this release."
        },
        "is_org_default": {
          "type": "boolean",
          "description": "Your stored org default voice (whether or not org_default_enabled is true)."
        },
        "preview_url": {
          "type": [
            "string",
            "null"
          ],
          "format": "uri",
          "description": "Recommended voices: a public mp3 of our real opening line (no auth; plays in an <audio> tag). Other voices: GET /voice/bridge/voices/{voice_id}/preview, which needs your API key (preview_requires_auth). null when the voice has no preview."
        },
        "preview_requires_auth": {
          "type": "boolean",
          "description": "Send Authorization: Bearer <your key> to fetch preview_url."
        },
        "usable_as_org_default": {
          "type": "boolean",
          "description": "On GET /voice/bridge/voices and /voices/{voice_id}: whether PATCH /voice/bridge/settings would accept this voice as the org default (active and native English; always true for the recommended set). Absent on the settings readback."
        }
      }
    },
    "BridgeVoiceWarning": {
      "type": "object",
      "required": [
        "path",
        "code",
        "message"
      ],
      "properties": {
        "path": {
          "type": "string"
        },
        "code": {
          "type": "string",
          "enum": [
            "voice_unverified",
            "voice_not_curated",
            "voice_not_english",
            "voice_verification_skipped",
            "org_settings_unavailable",
            "org_default_disabled",
            "stored_value_invalid",
            "org_default_auto_cleared",
            "numbers_unavailable",
            "voice_details_unavailable",
            "catalog_stale",
            "numbers_truncated"
          ]
        },
        "message": {
          "type": "string"
        }
      }
    }
  }
}