Skip to content

Recipe: OpenAI#

Connect an OpenAI model to the Torii Wallet door through OpenAI's hosted MCP tool and walk the mandate path. English only. Testnet (Base Sepolia, chain 84532).

Verified on 2026-10-13 against API 7abdf48bc (fixture server through a temporary tunnel), model gpt-5-mini, one turn, about three US cents. The Responses API path below was run with the plain openai SDK (3.29.0) and called all five tools. Not verified: see the end of this page.

What the bot needs#

Same as Grok Bot: the API host with the door open (GET /torii/door answers 402), an agent key in the header X-NW-User-Key, and your agent id. No exchange key and no wallet key. Do not paste a real key into a shared chat or a repository.

An OpenAI API key with prepaid credit. A ChatGPT Plus subscription does not include API credit: without a balance the call fails with HTTP 429 credit_balance_exhausted. Add a prepaid top-up (a five-dollar top-up covered the run below many times over).

Responses API, hosted MCP tool#

OpenAI's servers call your MCP server, so the host must be reachable from the internet (a tunnel works for a fixture).

from openai import OpenAI

client = OpenAI()
resp = client.responses.create(
    model="gpt-5-mini",
    input="Read <BASE>/torii/skill.md. You are agent 21. List your mandate offers, accept the first one, ...",
    tools=[{
        "type": "mcp",
        "server_label": "torii",
        "server_url": "https://<api-host>/mcp?profile=full",
        "headers": {"X-NW-User-Key": "<your agent key>"},
        "require_approval": "never",
    }],
)

The output carries one mcp_list_tools item, then an mcp_call item per tool call (name, arguments, output, error), then a message. If the model stops early, call again with previous_response_id.

Agents SDK, HostedMCPTool#

Not run; this is the same hosted tool configuration through the Agents SDK.

from agents import Agent, HostedMCPTool, Runner

agent = Agent(
    name="torii-bot",
    tools=[HostedMCPTool(tool_config={
        "type": "mcp",
        "server_label": "torii",
        "server_url": "https://<api-host>/mcp?profile=full",
        "headers": {"X-NW-User-Key": "<your agent key>"},
        "require_approval": "never",
    })],
)
result = Runner.run_sync(agent, "Read <BASE>/torii/skill.md. You are agent 21. ...")

ChatGPT app, custom connector#

Not verified (only the Responses API was run). Add a custom connector with the same URL and the key header, if the connector UI allows a static header (it may need developer mode). If it only supports OAuth, it cannot use this door yet; say so rather than working around it.

The probe#

python scripts/tw_recipe_openai_probe.py --base https://<host>
python scripts/tw_recipe_openai_probe.py --base https://<host> --dry-run   # prints the request, key redacted

It sends the Responses API request above, prints each mcp_list_tools and mcp_call, and exits 0 when mandate_offers, mandate_accept, mandate_report_event, mandate_get and mandate_report_refusal were all called. A live call needs pip install openai (in a venv).

The prompt used#

Read <BASE>/torii/skill.md. You are agent 21. List your mandate offers, accept the first one, report one buy event of 5 USDC with a fake tx hash and the target {"kind":"contract","chain_id":84532,"address":"0xabc"}, read the mandate back, then report a refusal with reason OverPerTxCap. Print each tool result.

What the verified run did#

One responses.create turn. The hosted tool listed 73 tools, then the model called, in order:

  1. mandate_offers returned one signed, designated offer.
  2. mandate_accept accepted it (agent 21).
  3. mandate_report_event recorded a buy of 5.00 USDC. The target object {"kind":"contract","chain_id":84532,"address":"0xabc"} was accepted and no violation was raised.
  4. mandate_get read the record back.
  5. mandate_report_refusal, first attempt: refused with invalid_parameter: tx_hash must be 0x followed by 64 hex digits (the model had sent 63 hex digits). The model corrected the hash and the second attempt was recorded.

Then the probe printed "WALK COMPLETE". Usage: input 24,990 tokens, output 11,578 tokens, about three US cents.

Owner notes#

  • Credit: a ChatGPT Plus subscription does not include API credit. The first attempt, before a prepaid top-up, failed with HTTP 429 credit_balance_exhausted. Top up the API account first.
  • Self-correction: the model fixed an invalid tx hash after reading the door's validation message. That is what the error contract is for: a refusal names the reason and says what to change, and an agent can act on it without a human. See Refusals.
  • The ChatGPT app custom connector path is not verified.

The first tool calls#

Same as Claude and Grok Bot: mandate_offers, mandate_accept, mandate_report_event, mandate_get, mandate_report_refusal. The owner step (/tw/start?agent=<your agent id>) is the same. When a call is refused, branch on reason: see Refusals.

Not verified#

  • A real deployed host. The run used a fixture server (a permissive fixture receipt) reached through a temporary tunnel.
  • Real chain receipts. The tx hashes were fake.
  • The ChatGPT app custom connector.
  • The Agents SDK path. Only the Responses API was run.