> Fetch clean Markdown by appending `.md` to any page URL under https://signalwire.com/docs or requesting it with the HTTP header `Accept: text/markdown`. The root index at https://signalwire.com/docs/llms.txt lists the available documentation indexes. # prepare > Validate a browser request and build the upstream JSON-RPC call, without FastAPI. [ref-chatgateway]: /docs/server-sdks/reference/python/agents/chat-gateway [router]: /docs/server-sdks/reference/python/agents/chat-gateway/router [aichatclient]: /docs/server-sdks/reference/python/agents/ai-chat-client Validate a browser request and build the upstream call. This is the framework-agnostic core of the gateway, for serving it from something other than FastAPI. With FastAPI, use [`router()`][router] instead. Everything the browser could use to widen its own access is either rejected or overwritten here: the method must be one of the four, the conversation comes from a signed handle, and `config_url` is the gateway's. ## **Parameters** **`body`** `dict[str, Any]` — required The parsed request body, carrying `method` and, depending on the method, `handle` and `message`. --- **`origin`** `str | None` — required The request's `Origin` header. Keyword-only. `None` is allowed, since a non-browser caller sends none and refusing those would break server-side use without stopping an attacker, who simply omits the header. --- **`key`** `str | None` — required The publishable key from `Authorization: Bearer`. Keyword-only. --- ## **Returns** `tuple[str, dict[str, Any], str | None]` — the upstream method name, its params, and a newly minted handle. The handle is set only on the call that created the conversation, so you can hand it back in the `X-Chat-Handle` header. The upstream method is the service's, not the browser's: `start` becomes `create_conversation`, `end` becomes `end_conversation`, and `log` becomes `chat_log`. ## **Raises** `GatewayRejection` for a bad key (`401`), a disallowed origin (`403`), a bad or expired handle (`403`), an unknown method or missing message (`400`), or a cap hit (`429`). ## **Example** Serving the gateway from a framework of your own, forwarding with [`AIChatClient`][aichatclient]: ```python {9,13} from signalwire.ai_chat import AIChatClient, ChatGateway, GatewayRejection client = AIChatClient(space="your-space") gateway = ChatGateway(config_url="https://bayview-taxi.example.com/swml", client=client) async def handle_request(body, origin, key): try: method, params, minted = gateway.prepare(body, origin=origin, key=key) except GatewayRejection as rejection: return rejection.status, {"error": rejection.reason}, None async with client.raw_post(method, params) as resp: payload = await resp.read() return 200, payload, minted ``` > Validate a browser request and build the upstream JSON-RPC call, without FastAPI.