# Schema Reference

> Complete reference of all Pydantic models used to define bot schemas. Each model shows fields with types, defaults, and descriptions.

## UIRouter (top-level)

Root model. Load with `UIRouter.model_validate(data)`.

| Field | Type | Default | Description |
|---|---|---|---|
| name | `str` | required | Bot name |
| version | `str` | `"1.0.0"` | Schema version |
| initial_scene | `str` | required | Must match a scene id |
| scenes | `list[Scene]` | required | All bot scenes |
| global_flags | `list[Flag]` | `[]` | Flags available in every scene |
| variables | `list[BotVariable]` | `[]` | Persistent variable definitions |
| conditional_flags | `list[ConditionalFlag]` | `[]` | Rule-engine-driven flags |
| global_handlers | `list[GlobalHandler]` | `[]` | Evaluated before scene handlers |
| events | `list[EventDefinition]` | `[]` | Event definitions |
| event_handlers | `list[EventHandler]` | `[]` | Handlers for named events |
| callback_strategy | `CallbackDataStrategy` | `type="inline"` | Callback data encoding |
| navigation | `NavigationConfig` | defaults | History and input settings |
| fallback | `FallbackConfig` | defaults | Handlers for unmatched input |
| custom_functions | `dict[str, str]` | `{}` | name -> Python import path |
| business_actions | `dict[str, str]` | `{}` | name -> Python import path |
| enable_fluent | `bool` | `False` | Enable Fluent localization |

## Scene

| Field | Type | Default | Description |
|---|---|---|---|
| id | `str` | required | Unique identifier |
| name | `str` | required | Human-readable name |
| description | `str \| None` | `None` | Optional description |
| flags | `list[Flag]` | `[]` | Scene-scoped flags |
| default_content | `MessageContent \| None` | `None` | Shown on scene entry |
| default_keyboard | `Keyboard \| DynamicKeyboard \| None` | `None` | Keyboard with default_content |
| conditional_content | `list[ConditionalContent]` | `[]` | Highest priority match overrides default_content |
| messages | `list[MessageContent]` | `[]` | Additional messages on entry |
| handlers | `list[Handler]` | `[]` | Scene event handlers |
| on_enter | `list[ActionInstruction]` | `[]` | Entry lifecycle hook |
| on_exit | `list[ActionInstruction]` | `[]` | Exit lifecycle hook |
| allowed_scenes | `list[str]` | `[]` | Reachable scene ids; empty = all |
| parent_scene | `str \| None` | `None` | For hierarchical navigation |
| expect_input | `bool` | `False` | Scene waits for text input |
| input_validator | `str \| None` | `None` | Registry function to validate input |

## Handler

| Field | Type | Default | Description |
|---|---|---|---|
| name | `str` | required | Unique within scene |
| event_type | `EventType` | required | Trigger event |
| filters | `list[Filter]` | `[]` | Narrow matching updates |
| conditions | `list[str]` | `[]` | Registry functions; ALL must return True |
| actions | `list[ActionInstruction]` | required | Actions to execute |
| require_state | `bool \| None` | `None` | Auto: MESSAGE->True, all others->False. Stateless event types always False. |
| throttle | `ThrottleConfig \| None` | `None` | Rate limiting |

## GlobalHandler

Same as Handler plus: `priority` (int, 0 -- higher=first), `interrupt_propagation` (bool, False). `require_state` defaults to False. **Note:** `filters` is required (no default) unlike Handler where it defaults to `[]`.

## ActionInstruction

Discriminated union on `type` field. Grouped by category:

**Navigation:** `GOTO_SCENE` (scene_id, transition), `BACK` (transition). scene_id=None re-enters current scene.

**Messaging:** `SEND_MESSAGE`, `EDIT_MESSAGE`, `SEND_PHOTO`, `SEND_VIDEO`, `SEND_DOCUMENT` all have: content (MessageContent|None), keyboard (Keyboard|DynamicKeyboard|None). `DELETE_MESSAGE` has no extra fields. `ANSWER_CALLBACK` has: callback_text (str|None), show_alert (bool, False).

**State:** `SAVE_INPUT` (save_as, params). `CLEAR_DATA` (data_keys -- None=clear all). `SET_VARIABLE` (variable_name, value, operation="set"|"increment"|"append", scope=USER).

**Events:** `SCHEDULE_EVENT` (event_name, schedule_type="once", schedule_value, event_data={}). `EMIT_EVENT` (event_name, event_data={}).

**Custom:** `BUSINESS_ACTION` (business_action, params={}). `CUSTOM` (function, function_params={}).

**Conditional:** `CONDITIONAL` (conditions: list[RuleCondition], then_actions, else_actions).

**Telegram:** `APPROVE_JOIN_REQUEST`, `DECLINE_JOIN_REQUEST` (no fields). `ANSWER_INLINE_QUERY` (results_function, results: list[InlineArticleResult], cache_time=300, is_personal=False, next_offset).

## MessageContent

| Field | Type | Default |
|---|---|---|
| text | `str \| DynamicContent \| LocalizedContent \| None` | `None` |
| media | `MediaContent \| None` | `None` |
| parse_mode | `str` | `"HTML"` |
| disable_web_page_preview | `bool` | `False` |

## DynamicContent

Discriminated by `type`: **"template"** (template: ContentTemplate with `{flag_name}` placeholders + flags list), **"function"** (function: registry name returning str), **"localized_template"** (localized_template: LocalizedTemplate).

## Flag / FlagGetter

Flag: `name` (str), `getter` (FlagGetter), `default` (Any, None).

FlagGetter discriminated by `type`: `"static"` (value), `"function"` (function: registry name), `"context"` (context_key), `"user_input"` (input_key).

## Filter

Discriminated by `type`:

| type | Key fields |
|---|---|
| `"command"` | `commands: list[str]` |
| `"text"` | `text: str \| list[str]` |
| `"regexp"` | `pattern: str` |
| `"content_type"` | `content_types: list[str]` |
| `"custom"` | `custom_function: str` |
| `"callback_data"` | `callback_data: str \| list[str]` |
| `"callback_data_regexp"` | `pattern: str` |
| `"chat_member"` | `chat_member_filter: ChatMemberFilter` |
| `"chattype"` | `chat_types: list[str]` |
| `"state"` | `state: str` |
| `"inline_command"` | (no extra fields) |
| `"inline_prefix"` | `prefix: str`, `sep: str \| None` |
| `"inline_data"` | (no extra fields) |

ChatMemberFilter: `preset` ("join"|"leave"|"promoted"|"demoted"|"any") or custom `old_status`/`new_status` lists.

## Keyboard / Button / DynamicKeyboard

**Button**: `text` (str|DynamicContent|LocalizedContent, required), `callback_action` (str|None -- scene handler name), `callback_global` (str|None -- global handler name), `url` (str|DynamicContent|None), `switch_inline_query` (str|None), `switch_inline_query_current_chat` (str|None), `switch_inline_query_chosen_chat` (SwitchInlineQueryChosenChat|None), `web_app_url` (str|None), `callback_params` (dict[str,str], {}), `style` ("danger"|"success"|"primary"|None), `icon_custom_emoji_id` (str|None).

**Keyboard**: `buttons` (list[list[Button]] -- rows), `is_inline` (True), `resize_keyboard` (False), `one_time_keyboard` (False).

**DynamicKeyboard**: `data_source` (str -- registry function), `layout` ("grid"|"list"|"inline", "grid"), `columns` (2), `button_template` (ButtonTemplate), `pagination` (PaginationConfig), `header_buttons`/`footer_buttons` (list[list[Button]], []), `is_inline` (True).

## Enums

**EventType**: MESSAGE, CALLBACK (callback_query), EDITED_MESSAGE, SCENE_ENTER, SCENE_EXIT, MY_CHAT_MEMBER, CHAT_MEMBER, CHAT_BOOST, REMOVED_CHAT_BOOST, CHAT_JOIN_REQUEST, PRE_CHECKOUT_QUERY, INLINE_QUERY, CHOSEN_INLINE_RESULT.

**ActionType**: SEND_MESSAGE, EDIT_MESSAGE, SEND_PHOTO, SEND_VIDEO, SEND_DOCUMENT, DELETE_MESSAGE, ANSWER_CALLBACK, GOTO_SCENE, BACK, SAVE_INPUT, CLEAR_DATA, SET_VARIABLE, SCHEDULE_EVENT, EMIT_EVENT, BUSINESS_ACTION, APPROVE_JOIN_REQUEST, DECLINE_JOIN_REQUEST, ANSWER_INLINE_QUERY, CUSTOM, CONDITIONAL.

**TransitionType**: `SEND` (new message), `EDIT_SMART` (edit if callback, else send), `ANSWER` (answer callback only).

**VariableScope**: USER, BOT, CHAT. **VariableType**: INT, FLOAT, BOOL, STR, DATETIME, JSON.

**ConditionOperator**: EQ, NE, GT, GTE, LT, LTE, IN, NOT_IN, CONTAINS, STARTS_WITH, ENDS_WITH.

**STATELESS_EVENT_TYPES** (no scene navigation): MY_CHAT_MEMBER, CHAT_MEMBER, CHAT_BOOST, REMOVED_CHAT_BOOST, CHAT_JOIN_REQUEST, PRE_CHECKOUT_QUERY, INLINE_QUERY, CHOSEN_INLINE_RESULT.

## Supporting Models

**RuleCondition**: `variable` (str), `operator` (ConditionOperator), `value` (Any).

**Rule**: `conditions` (list[RuleCondition]), `result` (Any), `priority` (int, 0).

**ConditionalFlag**: `name`, `rules` (list[Rule]), `default`, `description` (str|None).

**ConditionalContent**: `conditions` (list[RuleCondition]), `content` (MessageContent), `keyboard` (Keyboard|None), `priority` (int, 0).

**ThrottleConfig**: `max_calls` (int), `period_seconds` (int), `scope` (USER|CHAT|GLOBAL), `cooldown_action` (ActionInstruction|None).

**BotVariable**: `name`, `scope` (VariableScope), `type` (VariableType), `default` (None), `description` (str|None).

**EventDefinition**: `name`, `source_type` (INTERNAL|WEBHOOK|SCHEDULED|MANUAL), `schedule_type` (ScheduleType|None), `schedule_value`, `webhook_path`, `expected_data` ({}).

**EventHandler**: `event_name`, `conditions` ([]), `actions`, `priority` (0), `target_scope` ("user"|"bot"|"chat", "user").

**NavigationConfig**: `enable_history` (True), `max_history_depth` (10), `store_user_input` (True).

**CallbackDataStrategy**: `type` ("inline"|"cache"), `separator` (":"), `max_length` (64), `cache_prefix` ("cbd"), `ttl` (3600).

**FallbackConfig**: `unexpected_message`, `unexpected_callback`, `unexpected_edited_message`, `unexpected_inline_query` (all list[Handler], []), `stale_callback_text` (str).

**MediaContent**: `type` ("photo"|"video"|"document"|"audio"), `source` (str|DynamicContent), `caption` (str|DynamicContent|None).

**PaginationConfig**: `enabled` (False), `page_size` (10), `cache_ttl` (300), `prev_button_text`, `next_button_text`.

**ButtonTemplate**: `text`, `callback_action`, `callback_params` ({}), `url` (None), `condition` (None), `style` (None), `icon_custom_emoji_id` (None).

**InlineArticleResult**: `id` (str|None), `title` (str|DynamicContent), `description`, `message_text`, `parse_mode` ("HTML"), `thumbnail_url`.

**ContentTemplate**: `template` (str with `{flag}` placeholders), `flags` (list[str], []).

**LocalizedTemplate**: `translations` (dict[str,str]), `flags` ([]), `locale_flag` ("locale"), `default_locale` ("en").

**LocalizedContent**: `type` ("localized"), `translations` (dict[str,str]), `locale_getter` (str), `default_locale` ("en").
