{
  "openapi": "3.0.3",
  "info": {
    "title": "TelAPI",
    "description": "TelAPI issues SDK session tokens, exposes endpoint runtime capabilities, receives provider webhooks under /api/v1/webhooks, and hosts the /ws/session WebSocket channel. Authenticated REST endpoints require a team API key in the X-API-Key header with the documented scope for each operation.",
    "version": "edge"
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      },
      "apiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-API-Key",
        "description": "Team API key. Required scopes are documented on each authenticated endpoint."
      }
    },
    "schemas": {
      "ChannelMessage": {
        "type": "object",
        "description": "WebSocket message envelope exchanged on /ws/session. Include the payload object matching the message type.",
        "required": [
          "type",
          "sessionId",
          "messageId",
          "timestamp",
          "direction"
        ],
        "properties": {
          "type": {
            "type": "string",
            "enum": [
              "chat",
              "browser_action",
              "action",
              "action_result",
              "audio",
              "status",
              "control",
              "reconnect",
              "ping",
              "pong",
              "error"
            ]
          },
          "sessionId": {
            "type": "string"
          },
          "messageId": {
            "type": "string",
            "format": "uuid"
          },
          "streamId": {
            "type": "string",
            "description": "Redis stream id included on replayed runtime-to-browser messages."
          },
          "timestamp": {
            "type": "number",
            "description": "Unix timestamp in milliseconds."
          },
          "direction": {
            "type": "string",
            "enum": [
              "to_browser",
              "to_ari"
            ]
          },
          "chat": {
            "type": "object",
            "description": "Present when type is chat.",
            "additionalProperties": true
          },
          "browserAction": {
            "type": "object",
            "description": "Present when type is browser_action.",
            "additionalProperties": true
          },
          "action": {
            "type": "object",
            "description": "Present when type is action.",
            "additionalProperties": true
          },
          "actionResult": {
            "type": "object",
            "description": "Present when type is action_result.",
            "additionalProperties": true
          },
          "audio": {
            "type": "object",
            "description": "Present when type is audio.",
            "additionalProperties": true
          },
          "status": {
            "type": "object",
            "description": "Present when type is status.",
            "additionalProperties": true
          },
          "control": {
            "type": "object",
            "description": "Present when type is control; supports enable_text_chat and disable_text_chat commands.",
            "additionalProperties": true
          },
          "reconnect": {
            "type": "object",
            "description": "Present when type is reconnect.",
            "additionalProperties": true
          },
          "error": {
            "type": "object",
            "description": "Present when type is error.",
            "additionalProperties": true
          }
        }
      },
      "ErrorResponse": {
        "type": "object",
        "description": "Standard TelAPI error envelope.",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "description": "Stable machine-readable error code.",
                "example": "VALIDATION_ERROR"
              },
              "message": {
                "type": "string",
                "description": "Human-readable error summary.",
                "example": "Request validation failed"
              },
              "details": {
                "description": "Optional structured details, usually validation issues."
              },
              "requestId": {
                "type": "string",
                "description": "Fastify request id for log correlation when available."
              }
            }
          }
        }
      }
    }
  },
  "paths": {
    "/health": {
      "get": {
        "summary": "Service health",
        "tags": [
          "Health"
        ],
        "description": "Returns 200 when required dependencies (Redis) are reachable; otherwise 503. Minimal body — monitor detail via OpenTelemetry.",
        "responses": {
          "200": {
            "description": "Default Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "ok"
                      ]
                    }
                  }
                },
                "example": {
                  "status": "ok"
                }
              }
            }
          },
          "503": {
            "description": "Default Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "status"
                  ],
                  "properties": {
                    "status": {
                      "type": "string",
                      "enum": [
                        "error"
                      ]
                    }
                  }
                },
                "example": {
                  "status": "error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/webhooks/tobi/{channelId}": {
      "post": {
        "summary": "Receive TOBi chatbot callback",
        "tags": [
          "Webhooks"
        ],
        "description": "Receives message callbacks from Vodafone TOBi chatbot and forwards to TelPhi. Trace context (traceId, parentSpanId, callId) can be passed via query parameters for distributed tracing correlation. Each callback must include the per-conversation callback token in the token header.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "description": "Vodafone TOBi callback payload. TelAPI requires conversation.identifier.id so the response can be correlated to the TOBi channel.",
                "properties": {
                  "conversation": {
                    "type": "object",
                    "properties": {
                      "identifier": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string",
                            "description": "TOBi conversation identifier. Required by TelAPI."
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      }
                    }
                  },
                  "from": {
                    "type": "object",
                    "properties": {
                      "identifier": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "type": "string"
                          },
                          "name": {
                            "type": "string"
                          }
                        }
                      },
                      "avatar": {
                        "type": "string"
                      }
                    }
                  },
                  "messages": {
                    "type": "object",
                    "properties": {
                      "timestamp": {
                        "type": "string"
                      },
                      "message": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "required": [
                            "content"
                          ],
                          "properties": {
                            "messageId": {
                              "type": "number"
                            },
                            "relatesTo": {
                              "type": "number"
                            },
                            "sequence": {
                              "type": "number"
                            },
                            "content": {
                              "type": "object",
                              "properties": {
                                "textMessage": {
                                  "type": "object",
                                  "properties": {
                                    "textPlain": {
                                      "type": "string"
                                    },
                                    "textHtml": {
                                      "type": "string"
                                    },
                                    "textMarkdown": {
                                      "type": "string"
                                    }
                                  }
                                },
                                "voiceMessage": {
                                  "type": "string"
                                },
                                "event": {
                                  "type": "object",
                                  "properties": {
                                    "typing": {
                                      "type": "object",
                                      "required": [
                                        "enable"
                                      ],
                                      "properties": {
                                        "enable": {
                                          "type": "boolean"
                                        },
                                        "duration": {
                                          "type": "number"
                                        }
                                      }
                                    },
                                    "pause": {
                                      "type": "number"
                                    },
                                    "messageRead": {
                                      "type": "string"
                                    },
                                    "noInputExpected": {
                                      "type": "boolean"
                                    }
                                  }
                                }
                              }
                            }
                          }
                        }
                      }
                    }
                  },
                  "metadata": {
                    "type": "object",
                    "additionalProperties": true,
                    "description": "Provider metadata forwarded to TelPhi as JSON."
                  },
                  "channelData": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "additionalProperties": true
                    }
                  },
                  "nluData": {
                    "type": "object",
                    "properties": {
                      "intents": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "additionalProperties": true
                        }
                      },
                      "entities": {
                        "type": "array",
                        "items": {
                          "type": "object",
                          "additionalProperties": true
                        }
                      },
                      "sentiment": {
                        "type": "object",
                        "additionalProperties": true
                      }
                    }
                  }
                }
              },
              "example": {
                "conversation": {
                  "identifier": {
                    "id": "tobi-conversation-123",
                    "name": "Customer conversation"
                  }
                },
                "messages": {
                  "timestamp": "2026-05-06T00:00:00.000Z",
                  "message": [
                    {
                      "messageId": 1,
                      "sequence": 1,
                      "content": {
                        "textMessage": {
                          "textPlain": "How can I help you?"
                        }
                      }
                    }
                  ]
                },
                "metadata": {
                  "locale": "de-DE"
                }
              }
            }
          },
          "description": "Vodafone TOBi callback payload. TelAPI requires conversation.identifier.id so the response can be correlated to the TOBi channel."
        },
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[a-fA-F0-9]{32}$"
            },
            "in": "query",
            "name": "traceId",
            "required": false,
            "description": "Trace ID for distributed tracing (32-char hex)"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[a-fA-F0-9]{16}$"
            },
            "in": "query",
            "name": "parentSpanId",
            "required": false,
            "description": "Parent span ID for distributed tracing (16-char hex)"
          },
          {
            "schema": {
              "type": "string"
            },
            "in": "query",
            "name": "callId",
            "required": false,
            "description": "Call ID from voiceai:calls: for correlation"
          },
          {
            "schema": {
              "type": "string"
            },
            "in": "path",
            "name": "channelId",
            "required": true,
            "description": "The channel ID this callback belongs to (TOBi conversation ID)"
          },
          {
            "schema": {
              "type": "string"
            },
            "example": "<token>",
            "in": "header",
            "name": "token",
            "required": false,
            "description": "Per-conversation TOBi callback token. Vodafone submits this as the literal token header value."
          }
        ],
        "responses": {
          "200": {
            "description": "Default Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "received",
                    "streamId"
                  ],
                  "properties": {
                    "received": {
                      "type": "boolean"
                    },
                    "streamId": {
                      "type": "string",
                      "description": "Redis stream id for the forwarded TOBi response."
                    }
                  }
                },
                "example": {
                  "received": true,
                  "streamId": "1778022191343-0"
                }
              }
            }
          },
          "400": {
            "description": "Invalid TOBi payload or missing conversation identifier",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Invalid TOBi payload or missing conversation identifier",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "INVALID_PAYLOAD",
                    "message": "Invalid TOBi payload or missing conversation identifier"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing, expired, or invalid TOBi callback token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Missing, expired, or invalid TOBi callback token",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "examples": {
                  "example1": {
                    "value": {
                      "error": {
                        "code": "TOBI_CALLBACK_TOKEN_MISSING",
                        "message": "Missing TOBi callback token. Provide the token header with the callback token value."
                      }
                    }
                  },
                  "example2": {
                    "value": {
                      "error": {
                        "code": "TOBI_CALLBACK_TOKEN_NOT_REGISTERED",
                        "message": "No active TOBi callback security token found for this webhook channel. The conversation may not be initialized or the session token may have expired."
                      }
                    }
                  },
                  "example3": {
                    "value": {
                      "error": {
                        "code": "TOBI_CALLBACK_TOKEN_INVALID",
                        "message": "Invalid TOBi callback token. The provided token header value does not match the active session token."
                      }
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Unexpected server error",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "INTERNAL_ERROR",
                    "message": "Unexpected server error"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/sessions/token": {
      "post": {
        "summary": "Request a session token",
        "tags": [
          "Sessions"
        ],
        "description": "Issues a runtime session id and a short-lived WebSocket token for the requested SDK mode.\n\nAfter this call, connect the browser SDK to:\n  /ws/session?sessionId={sessionId}&token={wsToken}\n\nWebSocket wire format:\n- Messages use the ChannelMessage envelope (see components.schemas.ChannelMessage).\n- The server sends an initial status message with state=connected.\n\nWebSocket close codes:\n- 4001 — missing sessionId or token\n- 4003 — invalid token or expired session\n- 4000 — superseded by a newer connection\n- 4500 — internal server error\n\nAuthentication: requires a team API key with CREATE_CALL_TOKEN scope.\n\nvoice_conversation responses also include WebRTC gateway metadata (telproDomain, webrtcGatewayUrl).",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "endpointId",
                  "mode"
                ],
                "properties": {
                  "endpointId": {
                    "type": "string",
                    "format": "uuid",
                    "description": "Endpoint to open a session against. It must belong to the API key team.",
                    "example": "0f6c3d4e-8b8f-4c59-9d0e-7e5e3b1f7f0f"
                  },
                  "mode": {
                    "type": "string",
                    "enum": [
                      "text",
                      "audio_playback",
                      "voice_conversation",
                      "browser_actions",
                      "listen"
                    ],
                    "description": "Session mode to provision: text chat, browser TTS playback, WebRTC voice, browser action dispatch, or interpretation listening."
                  }
                }
              },
              "examples": {
                "request_text_capability": {
                  "summary": "Request a text session",
                  "value": {
                    "endpointId": "0f6c3d4e-8b8f-4c59-9d0e-7e5e3b1f7f0f",
                    "mode": "text"
                  }
                },
                "request_audio_playback_capability": {
                  "summary": "Request an audio playback session",
                  "value": {
                    "endpointId": "0f6c3d4e-8b8f-4c59-9d0e-7e5e3b1f7f0f",
                    "mode": "audio_playback"
                  }
                },
                "request_voice_capability": {
                  "summary": "Request a voice conversation session",
                  "value": {
                    "endpointId": "0f6c3d4e-8b8f-4c59-9d0e-7e5e3b1f7f0f",
                    "mode": "voice_conversation"
                  }
                },
                "request_browser_actions_capability": {
                  "summary": "Request a browser actions session",
                  "value": {
                    "endpointId": "0f6c3d4e-8b8f-4c59-9d0e-7e5e3b1f7f0f",
                    "mode": "browser_actions"
                  }
                }
              }
            }
          }
        },
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Default Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "sessionId",
                    "wsToken",
                    "wsTokenExpiresIn",
                    "expiresIn"
                  ],
                  "properties": {
                    "sessionId": {
                      "type": "string",
                      "description": "The runtime session id (also the X-Call-ID for voice)"
                    },
                    "wsToken": {
                      "type": "string",
                      "description": "WebSocket token for /ws/session authentication"
                    },
                    "wsTokenExpiresIn": {
                      "type": "number",
                      "description": "WS token validity in seconds (5 min)"
                    },
                    "expiresIn": {
                      "type": "number",
                      "description": "Session token validity in seconds"
                    },
                    "telproDomain": {
                      "type": "string",
                      "description": "WebRTC gateway / TURN / STUN host (voice_conversation only)"
                    },
                    "webrtcGatewayUrl": {
                      "type": "string",
                      "description": "WebSocket URL of the WebRTC gateway (voice_conversation only)"
                    },
                    "traceId": {
                      "type": "string",
                      "description": "OpenTelemetry trace id returned for voice_conversation sessions."
                    },
                    "spanId": {
                      "type": "string",
                      "description": "OpenTelemetry root span id returned for voice_conversation sessions."
                    }
                  }
                },
                "examples": {
                  "example_text_capability": {
                    "summary": "Text session token",
                    "value": {
                      "sessionId": "call-loc5q7g0-k7p3f9x2",
                      "wsToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                      "wsTokenExpiresIn": 300,
                      "expiresIn": 3600
                    }
                  },
                  "example_voice_capability": {
                    "summary": "Voice conversation session token",
                    "value": {
                      "sessionId": "call-loc5q7g0-k7p3f9x2",
                      "wsToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
                      "wsTokenExpiresIn": 300,
                      "expiresIn": 3600,
                      "telproDomain": "telpro.example.com",
                      "webrtcGatewayUrl": "wss://telpro.example.com",
                      "traceId": "4bf92f3577b34da6a3ce929d0e0e4736",
                      "spanId": "00f067aa0ba902b7"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Request validation failed",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "VALIDATION_ERROR",
                    "message": "Request validation failed"
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key is missing or invalid",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "API key is missing or invalid",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "AUTHENTICATION_ERROR",
                    "message": "API key is missing or invalid"
                  }
                }
              }
            }
          },
          "403": {
            "description": "Forbidden: wrong team, origin/IP rejected, missing scope, or subscription limit reached",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Forbidden: wrong team, origin/IP rejected, missing scope, or subscription limit reached",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "FORBIDDEN",
                    "message": "Forbidden: wrong team, origin/IP rejected, missing scope, or subscription limit reached"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Endpoint not found",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "NOT_FOUND",
                    "message": "Endpoint not found"
                  }
                }
              }
            }
          },
          "409": {
            "description": "Endpoint flow is not configured or not synced for the requested mode",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Endpoint flow is not configured or not synced for the requested mode",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "FLOW_NOT_CONFIGURED",
                    "message": "Endpoint flow is not configured or not synced for the requested mode"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many requests",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Too many requests",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "RATE_LIMIT_EXCEEDED",
                    "message": "Too many requests"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Unexpected server error",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "INTERNAL_ERROR",
                    "message": "Unexpected server error"
                  }
                }
              }
            }
          },
          "503": {
            "description": "voice_conversation requested but TelPro is not configured",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "voice_conversation requested but TelPro is not configured",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "TELPRO_UNCONFIGURED",
                    "message": "voice_conversation requested but TelPro is not configured"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/runtime/capabilities": {
      "get": {
        "summary": "Discover endpoint runtime capabilities",
        "tags": [
          "Runtime"
        ],
        "description": "Returns the interaction modes, transport preferences, flow entry points, and browser actions the SDK can use for an endpoint. Requires a team API key with CREATE_CALL_TOKEN scope.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "example": "0f6c3d4e-8b8f-4c59-9d0e-7e5e3b1f7f0f",
            "in": "query",
            "name": "endpointId",
            "required": true,
            "description": "Endpoint to inspect. Must belong to the API key team."
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Default Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "endpointId",
                    "flowDefinitionId",
                    "runtime",
                    "interactionModes",
                    "transports",
                    "flows"
                  ],
                  "properties": {
                    "endpointId": {
                      "type": "string",
                      "format": "uuid"
                    },
                    "flowDefinitionId": {
                      "type": [
                        "null",
                        "string"
                      ],
                      "format": "uuid",
                      "description": "Active flow definition id, or null when the endpoint has no linked flow."
                    },
                    "runtime": {
                      "type": "object",
                      "required": [
                        "sessionContinuity",
                        "migration"
                      ],
                      "properties": {
                        "sessionContinuity": {
                          "type": "string",
                          "enum": [
                            "supported"
                          ]
                        },
                        "migration": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "text_to_voice",
                              "api_to_media"
                            ]
                          }
                        }
                      }
                    },
                    "interactionModes": {
                      "type": "object",
                      "required": [
                        "text",
                        "audio_playback",
                        "voice_conversation",
                        "browser_actions",
                        "listen"
                      ],
                      "properties": {
                        "text": {
                          "type": "boolean"
                        },
                        "audio_playback": {
                          "type": "boolean"
                        },
                        "voice_conversation": {
                          "type": "boolean"
                        },
                        "browser_actions": {
                          "type": "boolean"
                        },
                        "listen": {
                          "type": "boolean"
                        }
                      }
                    },
                    "transports": {
                      "type": "object",
                      "required": [
                        "preferred",
                        "available"
                      ],
                      "properties": {
                        "preferred": {
                          "type": "array",
                          "description": "Transports ordered by SDK preference.",
                          "items": {
                            "type": "string",
                            "enum": [
                              "rest",
                              "websocket",
                              "existing_media",
                              "webrtc"
                            ]
                          }
                        },
                        "available": {
                          "type": "array",
                          "description": "Every transport this endpoint can support.",
                          "items": {
                            "type": "string",
                            "enum": [
                              "rest",
                              "websocket",
                              "existing_media",
                              "webrtc"
                            ]
                          }
                        }
                      }
                    },
                    "flows": {
                      "type": "object",
                      "required": [
                        "entryPoints",
                        "responseModes",
                        "sideFlows",
                        "browserActions"
                      ],
                      "properties": {
                        "entryPoints": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "phone",
                              "web_voice",
                              "web_chat"
                            ]
                          }
                        },
                        "responseModes": {
                          "type": "array",
                          "items": {
                            "type": "string",
                            "enum": [
                              "audio_stream",
                              "text_stream",
                              "json",
                              "none"
                            ]
                          }
                        },
                        "sideFlows": {
                          "type": "array",
                          "description": "Advanced side flows that are not generated Browser-Originated Action capabilities.",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "triggerType"
                            ],
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "name": {
                                "type": "string"
                              },
                              "triggerType": {
                                "type": "string"
                              },
                              "messageType": {
                                "type": "string",
                                "description": "WebSocket message type when triggerType is ws_message."
                              }
                            }
                          }
                        },
                        "browserActions": {
                          "type": "array",
                          "items": {
                            "type": "object",
                            "required": [
                              "id",
                              "slug",
                              "label",
                              "type",
                              "messageType",
                              "voiceInvocable"
                            ],
                            "properties": {
                              "id": {
                                "type": "string"
                              },
                              "slug": {
                                "type": "string"
                              },
                              "label": {
                                "type": "string"
                              },
                              "type": {
                                "type": "string"
                              },
                              "messageType": {
                                "type": "string"
                              },
                              "voiceInvocable": {
                                "type": "boolean"
                              }
                            }
                          }
                        }
                      }
                    }
                  }
                },
                "example": {
                  "endpointId": "0f6c3d4e-8b8f-4c59-9d0e-7e5e3b1f7f0f",
                  "flowDefinitionId": "7e0dca65-b70b-461e-9d12-c18e0ab6e626",
                  "runtime": {
                    "sessionContinuity": "supported",
                    "migration": [
                      "text_to_voice",
                      "api_to_media"
                    ]
                  },
                  "interactionModes": {
                    "text": true,
                    "audio_playback": true,
                    "voice_conversation": true,
                    "browser_actions": true,
                    "listen": true
                  },
                  "transports": {
                    "preferred": [
                      "rest",
                      "websocket",
                      "existing_media",
                      "webrtc"
                    ],
                    "available": [
                      "rest",
                      "websocket",
                      "existing_media",
                      "webrtc"
                    ]
                  },
                  "flows": {
                    "entryPoints": [
                      "web_chat",
                      "web_voice"
                    ],
                    "responseModes": [
                      "json",
                      "audio_stream"
                    ],
                    "sideFlows": [],
                    "browserActions": [
                      {
                        "id": "read-selection",
                        "slug": "read-selection",
                        "label": "Read aloud",
                        "type": "readAloud",
                        "messageType": "browser.action.readAloud",
                        "voiceInvocable": true
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Request validation failed",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "VALIDATION_ERROR",
                    "message": "Request validation failed"
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key is missing or invalid",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "API key is missing or invalid",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "AUTHENTICATION_ERROR",
                    "message": "API key is missing or invalid"
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required scope or resource access",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "API key lacks the required scope or resource access",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "AUTHORIZATION_ERROR",
                    "message": "API key lacks the required scope or resource access"
                  }
                }
              }
            }
          },
          "404": {
            "description": "Endpoint not found for this team",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Endpoint not found for this team",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "ENDPOINT_NOT_FOUND",
                    "message": "Endpoint not found for this team"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many requests",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Too many requests",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "RATE_LIMIT_EXCEEDED",
                    "message": "Too many requests"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Unexpected server error",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "INTERNAL_ERROR",
                    "message": "Unexpected server error"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/endpoints": {
      "get": {
        "summary": "List team endpoints",
        "tags": [
          "Endpoints"
        ],
        "description": "Returns all endpoints belonging to the team associated with the API key. Requires a team API key with READ_TEAM_APPS scope.",
        "parameters": [
          {
            "schema": {
              "type": "string",
              "pattern": "^[1-9][0-9]*$",
              "default": "1"
            },
            "example": "1",
            "in": "query",
            "name": "page",
            "required": false,
            "description": "Page number (1-based)"
          },
          {
            "schema": {
              "type": "string",
              "pattern": "^[1-9][0-9]*$",
              "default": "20"
            },
            "example": "20",
            "in": "query",
            "name": "limit",
            "required": false,
            "description": "Items per page (max 100)"
          }
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "responses": {
          "200": {
            "description": "Default Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "endpoints",
                    "pagination"
                  ],
                  "properties": {
                    "endpoints": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "required": [
                          "id",
                          "name"
                        ],
                        "properties": {
                          "id": {
                            "type": "string",
                            "format": "uuid",
                            "description": "Endpoint id to use with runtime/session APIs."
                          },
                          "name": {
                            "type": "string",
                            "description": "Endpoint display name."
                          }
                        }
                      }
                    },
                    "pagination": {
                      "type": "object",
                      "required": [
                        "total",
                        "page",
                        "limit",
                        "totalPages"
                      ],
                      "properties": {
                        "total": {
                          "type": "number",
                          "description": "Total matching items."
                        },
                        "page": {
                          "type": "number",
                          "description": "Current 1-based page number."
                        },
                        "limit": {
                          "type": "number",
                          "description": "Items requested per page."
                        },
                        "totalPages": {
                          "type": "number",
                          "description": "Total pages available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "endpoints": [
                    {
                      "id": "0f6c3d4e-8b8f-4c59-9d0e-7e5e3b1f7f0f",
                      "name": "Website assistant"
                    }
                  ],
                  "pagination": {
                    "total": 1,
                    "page": 1,
                    "limit": 20,
                    "totalPages": 1
                  }
                }
              }
            }
          },
          "400": {
            "description": "Request validation failed",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Request validation failed",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "VALIDATION_ERROR",
                    "message": "Request validation failed"
                  }
                }
              }
            }
          },
          "401": {
            "description": "API key is missing or invalid",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "API key is missing or invalid",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "AUTHENTICATION_ERROR",
                    "message": "API key is missing or invalid"
                  }
                }
              }
            }
          },
          "403": {
            "description": "API key lacks the required scope or resource access",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "API key lacks the required scope or resource access",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "AUTHORIZATION_ERROR",
                    "message": "API key lacks the required scope or resource access"
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many requests",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Too many requests",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "RATE_LIMIT_EXCEEDED",
                    "message": "Too many requests"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Unexpected server error",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "description": "Unexpected server error",
                  "required": [
                    "error"
                  ],
                  "properties": {
                    "error": {
                      "type": "object",
                      "required": [
                        "code",
                        "message"
                      ],
                      "properties": {
                        "code": {
                          "type": "string",
                          "description": "Stable machine-readable error code.",
                          "example": "VALIDATION_ERROR"
                        },
                        "message": {
                          "type": "string",
                          "description": "Human-readable error summary.",
                          "example": "Request validation failed"
                        },
                        "details": {
                          "description": "Optional structured details, usually validation issues."
                        },
                        "requestId": {
                          "type": "string",
                          "description": "Fastify request id for log correlation when available."
                        }
                      }
                    }
                  }
                },
                "example": {
                  "error": {
                    "code": "INTERNAL_ERROR",
                    "message": "Unexpected server error"
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "servers": [
    {
      "url": "http://localhost:3001",
      "description": "Development server"
    }
  ],
  "tags": [
    {
      "name": "Endpoints",
      "description": "Team endpoint discovery using team API keys"
    },
    {
      "name": "Health",
      "description": "GET /health — minimal probe (Redis); detail via OpenTelemetry"
    },
    {
      "name": "Runtime",
      "description": "Runtime capability discovery for SDK clients"
    },
    {
      "name": "Sessions",
      "description": "Session-token issuance for text, audio playback, voice, and browser-action SDK modes"
    },
    {
      "name": "Webhooks",
      "description": "Webhook receivers"
    }
  ]
}
