https://api.qxlabs.com/v1 with your QX API key and call responses.create. model names the agent, builtin:qx_agent for the QX agent or an agent’s ID from its URL in the app. Each snippet below has cURL, Python and TypeScript tabs, and each one runs as it is once your key replaces <YOUR_QX_API_KEY>.
Set up the client
Install the SDK withpip install openai or npm install openai, then create a client with your key. With cURL there’s nothing to set up: every call sends the key as a bearer token.
Send a message
A message is one call. The reply’s text is inoutput_text, and output holds everything the agent did: its thinking as reasoning items, each tool call as an mcp_call item, and its message. To send a file, make the message a list with input_text and input_file parts, with the file as a base64 data URL.
Continue a conversation
Send the last response’sid as previous_response_id, or the conversation’s ID as conversation. Either one keeps the whole conversation, which you can also open in the app’s chat. A message with neither starts a new conversation.
Stream the reply
Setstream to true to get the Responses API’s events as they happen, or use the SDK’s stream helper, which also gives you the final response. A call without streaming must finish within 240 seconds, so stream anything long. To stop an agent while it works, cancel any response of its conversation. What the agent already did stays.
Approvals
Some tools need approval before they run, like sending an email.permission_mode decides what happens, for that message only: delegated (the default) refuses the tool, normal makes the agent ask first, and auto lets it run. It’s QX’s own field, so Python sends it in extra_body and TypeScript needs a type that allows it.
In normal mode the response ends with mcp_approval_request items, each with the call’s arguments and the agent’s reason. Answer with mcp_approval_response items in input, on the same conversation and with no message, and the turn carries on. Each answer covers its one call.
Choose an app account
When you have more than one account for an app, like two Gmail accounts, the agent uses the app’s default. To use another one, sendconnected_accounts with the app and the account’s ID. The connected accounts endpoint lists yours. It’s a QX endpoint, so the SDKs read it with their own get.
Read the history
conversations.items.list returns a conversation’s messages and tool calls, newest first. limit counts turns, a user message and everything after it, and the SDKs fetch the next pages as you go.
Good to know
- Tool calls come back as
mcp_callitems. A call to one of QX’s own tools shows only the command, search words, URL or path it was given, a call to an app’s tool shows no arguments, andoutputis always null. A failed call has its reason inerror. - The agent’s thinking comes as
reasoningitems, and its tokens are inusage.output_tokens_details.reasoning_tokens. - A message sent while the conversation is still answering the last one joins that turn, and the response carries
steered: true. - Errors come in OpenAI’s shape, so the SDKs raise their usual errors. An org out of credits gets a 429 with code
insufficient_quotabefore any stream starts. The SDKs don’t resend a message that failed, because the API asks them not to.