For developers
The web API
Every tool is also an HTTP endpoint. Call it from your server with an access key.
Every tool an assistant sees is also POST /v1/<tool>. Send the tool’s arguments as a JSON object, and you get back the same JSON the assistant sees. Make a key first and keep it in XOR_KEY.
curl https://systemofreason.com/v1/kv \
-H "Authorization: Bearer $XOR_KEY" \
-H "Content-Type: application/json" \
-d '{"op":"set","key":"greeting","value":"hello"}'
const res = await fetch("https://systemofreason.com/v1/kv", {
method: "POST",
headers: { Authorization: `Bearer ${process.env.XOR_KEY}`, "Content-Type": "application/json" },
body: JSON.stringify({ op: "get", key: "greeting" }),
});
const data = await res.json();
Endpoints
| Request | What it does |
|---|---|
GET /v1 |
Lists the tools, with each one’s input schema. |
GET /v1/openapi.json |
Describes every tool as OpenAPI. |
POST /v1/<tool> |
Calls a tool with its arguments as JSON. |
PUT /v1/files/<space>/<path> |
Uploads a file’s raw bytes, up to 100 MiB. Send a Content-Length; the Content-Type becomes the file’s type. |
GET /v1/files/<space>/<path> |
Downloads a file’s raw bytes. |
The default file space is named default. Add ?project=<name> to the file routes outside the default project.
Rules
- Only access keys work here, not the OAuth tokens that apps get.
- There’s no CORS. Call it from a server, not a browser, so your key stays secret.
- Errors come back as
{"error": {"code": "...", "message": "..."}}, and the message says what to do.
| Code | Status | Meaning |
|---|---|---|
invalid_inputs |
400 | The arguments don’t fit the tool. |
forbidden |
403, or 401 with no key | No key was sent, or this key or account can’t do that: say, a site a secret isn’t allowed on, or a suspended account. |
not_found |
404 | No such tool or thing. |
limit_reached |
402 | The key hit its monthly cap, or an agent its budget. |
read_only |
409 | The account is out of credit or at its monthly limit, or the key is read-only. |
conflict |
409 | It clashes with what exists. |
rate_limited |
429 | Too many calls; wait a moment. |
upstream |
502 | The other site failed (from http). |
unsupported |
501 | Can’t be done here; don’t retry. |
internal |
500 | Our fault; try again. |
More examples
Make a table and add a row, all or nothing:
curl https://systemofreason.com/v1/sql -H "Authorization: Bearer $XOR_KEY" -H "Content-Type: application/json" \
-d '{"op":"batch","statements":[{"sql":"CREATE TABLE IF NOT EXISTS leads (name TEXT, note TEXT)"},{"sql":"INSERT INTO leads VALUES (?, ?)","params":["Ada","wants a demo"]}]}'
Save a small file, then upload a big one as raw bytes:
curl https://systemofreason.com/v1/files -H "Authorization: Bearer $XOR_KEY" -H "Content-Type: application/json" \
-d '{"op":"put","path":"notes/today.txt","content":"Call Ada about the demo."}'
curl -X PUT https://systemofreason.com/v1/files/default/reports/q3.pdf \
-H "Authorization: Bearer $XOR_KEY" -H "Content-Type: application/pdf" --data-binary @q3.pdf