Write once. Ship to every surface.
Every operation in the product is an action. The JSON API, the OpenAPI spec and the MCP tool list all describe the same actions — one schema, one set of permissions, one audit trail. Learn the pattern once and use it everywhere.
- A JSON API for every operation
- An OpenAPI 3.1 spec to generate a client from
- MCP for your own AI agent
Create a CRM deal.
The simplest meaningful API call. Same shape in every language. Same audit row in every case.
Every example works today with an API key from your security settings. Official client libraries are not published yet; generate a typed client from the OpenAPI spec in the meantime.
| 1 | curl -X POST https://app.odexy.app/api/actions/crm.deal.create \ |
| 2 | -H "Authorization: Bearer $ODEXY_API_KEY" \ |
| 3 | -H "Content-Type: application/json" \ |
| 4 | -d '{ |
| 5 | "title": "Q3 expansion", |
| 6 | "amount": 1500000, |
| 7 | "currency": "USD", |
| 8 | "stage": "discovery" |
| 9 | }' |
Events to your service.
An automation can call your endpoint when a business event happens — a deal won, an invoice paid, a ticket resolved — with the headers and body you choose. Put a shared secret in a header and check it before acting. Support ticket events can also be delivered as signed webhooks, registered through the API. Full webhook reference →
| 1 | import express from 'express'; |
| 2 | import { timingSafeEqual } from 'node:crypto'; |
| 3 | |
| 4 | const app = express(); |
| 5 | const expected = Buffer.from(process.env.ODEXY_SHARED_SECRET!); |
| 6 | |
| 7 | // The automation's HTTP step sends X-Shared-Secret with the value you set. |
| 8 | app.post('/hooks/odexy', express.json(), (req, res) => { |
| 9 | const got = Buffer.from(req.get('x-shared-secret') ?? ''); |
| 10 | if (got.length !== expected.length || !timingSafeEqual(got, expected)) { |
| 11 | return res.status(401).end(); |
| 12 | } |
| 13 | // req.body is exactly the body you built on the step. |
| 14 | res.status(200).end(); |
| 15 | }); |
Bring your own AI agent.
The MCP endpoint offers every action your API key allows — except ones marked irreversible, which stay in the app — to any MCP-compatible client: Cursor, Claude, your own agent. MCP details →
| 1 | { |
| 2 | "mcpServers": { |
| 3 | "odexy": { |
| 4 | "url": "https://app.odexy.app/api/mcp", |
| 5 | "headers": { |
| 6 | "Authorization": "Bearer YOUR_API_KEY" |
| 7 | } |
| 8 | } |
| 9 | } |
| 10 | } |
Six concepts. That's the whole API.
One action layer
Every user-performable operation is an action. The UI, the AI, the MCP server, and the API all call the same one.
Zod schemas as the contract
Every action declares its input + output via Zod. The OpenAPI spec is generated from these schemas; the MCP tool list is too.
Permission inheritance
API tokens carry a permission set. Actions outside that set are rejected before the handler runs.
An audit row for every change
Every change — and every refused or failed call — writes an audit row with the actor and the full input and output, in a log chained daily.
Idempotency keys
Send an Idempotency-Key header. Actions that support it, such as sending an email, return the original result for a repeat instead of acting twice.
Events to your service
An automation can call your endpoint when a business event happens; support ticket events can also arrive as signed webhooks.
Plain HTTP, and a spec to generate from.
- HTTP — first-class rather than a fallback. Every action is reachable as a JSON POST with an API key.
- OpenAPI spec — generated from the same Zod schemas the API validates against and served by the app; generate a typed client in any language from it.
- Official client libraries — not published. Call the API directly, as in the examples above, or generate a client from the spec.
Built on
the stack your engineers will recognize
Read the docs. Write your first action.
The API, the OpenAPI spec and the MCP tool list all speak actions. Learn the pattern once; use it everywhere.
