Reach a Workbench over HTTP
Goal: Call a hosted workbench's tools from any HTTP client: curl, Postman, or a backend.
A hosted workbench with its API mode on serves every tool method as a REST route. The author declares no
routes: the same .Tools({...}) declaration that the MCP mode shows as tools, the API mode shows as paths. This
page is for the caller. The overview of all three modes is Reach a Hosted Workbench.
Before you start
- A hosted workbench with the API mode on: see Host Your Own Workbench.
- A key from APIs -> API Keys, while the workspace's API identity (set in the API Manager) is Team (the default) or Hybrid. It needs no particular access right. Under App Identity, team keys are turned away and a caller needs an access token from an App Identity you trust.
- Any HTTP client. Make the call from a server, not from a page: the key travels with every request, and code that runs in a visitor's browser shows it to the visitor.
The address
https://openx.fathym.com/ox-api/w/<workspace id>/workbenches/<apiSlug>/API/<tool>/<method>
Every tool method is a POST route. The tool and method names are lowercased in the path (a tool called
Hello with a method Greet is .../API/hello/greet), and spaces in a tool name become hyphens. The API segment
is the mode's key and is case-sensitive. The slug in the examples (api-sample) is a stand-in: use your own
workbench's APISlug. <workspace id> is the ID shown in Workspace -> Settings.
Call it
curl -X POST 'https://openx.fathym.com/ox-api/w/<workspace id>/workbenches/api-sample/API/hello/greet' \
-H 'Authorization: Bearer <YOUR_TOKEN>' \
-H 'Content-Type: application/json' \
-d '{"arg0": "world"}'
The same call from code:
const res = await fetch('https://openx.fathym.com/ox-api/w/<workspace id>/workbenches/api-sample/API/hello/greet', {
method: 'POST',
headers: {
'Authorization': `Bearer ${token}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ arg0: 'world' }),
});
How arguments are sent
The body is a JSON object, and its shape follows how the method was declared:
| The method takes | Send |
|---|---|
| One object argument | The object's fields directly: { "field": value, ... } |
| One or more plain values | Positional keys: { "arg0": ..., "arg1": ... } |
| A tool the author gave no input schema | One field holding JSON as text: { "input": "{\"id\": 7}" } |
The first two rows cover a tool with a declared input schema. A tool that needs set-up before its methods run also
accepts a Setup field in the body. The catalog below does not list argument names: they come from the author's
code, so ask the author, or read the workbench's source.
The OpenAPI catalog
Every API-mode workbench describes its own routes:
GET https://openx.fathym.com/ox-api/w/<workspace id>/workbenches/<apiSlug>/API/openapi.json
It takes the same Authorization header as every other call. It lists each route with its summary, and its request
and response bodies are empty objects: it carries no argument names and no types. Save it, then feed it to
anything that reads OpenAPI:
curl 'https://openx.fathym.com/ox-api/w/<workspace id>/workbenches/api-sample/API/openapi.json' \
-H 'Authorization: Bearer <YOUR_TOKEN>' -o api-sample.openapi.json
npx @hey-api/openapi-ts --input api-sample.openapi.json --output ./src/generated
The second command makes a TypeScript client with one function per route; its bodies are untyped, because the
catalog has no schemas. It is an example of a generator, not part of OpenX. To explore the routes in Postman,
import the saved file, and add the Authorization header at the collection level. Insomnia, Bruno and other
OpenAPI tools work the same way.
In the API Manager
APIs -> API Manager -> Workbench APIs lists each workbench with its API mode on: the Base URL, and each
route with a cURL line. The tab reads the catalog once, during the deploy. If it still says "No route catalog yet"
after the deploy, deploy again; the live .../API/openapi.json above answers whenever the container is up.
One declaration, three doors
The API and MCP modes read the same tool declaration. Turn on both for one workbench and every method is both a REST route and an MCP tool, with the same code behind it. Each enabled mode runs in its own container.
What a call is checked against
Every call needs the key (the Authorization header). No access right is required: a caller the API identity
admits reaches every route of every mode that is on. There is no per-mode or per-route right today.
If something's off
| Issue | Do |
|---|---|
| The client cannot connect | Check the address. The API segment is case-sensitive and must be a mode the workbench has turned on |
401 | The key has expired, or the API identity is App Identity, which turns team keys away. Make a new key, or use an App Identity token |
404 on a route | The path is the tool name and method name, lowercased. Read the catalog to see what is served |
| An empty catalog in the API Manager | Deploy again. The tab reads the catalog once, during the deploy. The live .../API/openapi.json works whenever the container is up |
503 | "is not deployed yet": the mode has no container yet. Deploy the workspace, or wait for a deploy that is running to finish |
| The first call after a quiet spell is slow | A mode with a web address can scale down to no containers when idle (the default). The first call starts one; later calls are quick. Set Min replicas to 1 in the Hosting tab to keep one running |
| Arguments do not arrive | Match the table above: an object argument is sent as fields, plain values as arg0, arg1 |
Next steps
- Connect an AI -> Reach a Workbench over MCP
- Serve a page -> Reach a Workbench from a page
- Host another -> Host Your Own Workbench
- Keys and expiry -> Auth & Tokens