For developers · api-first · yours to extend

Your schema is
the api.

Define a table and its REST endpoints already exist. Add logic in TypeScript, secure every read with one rule, and ship it as a file you own in git. No codegen. No redeploy.

Read the docs GitHub

The same primitives back a Saturday prototype and a company's system of record.

zero → running
$ curl -fsSL https://get.oikapi.com/cli | sh
$ oi login https://hq.oikapi.com
 authorized, saved to keychain

$ oi init crm && cd crm
$ oi dev
 watching crm/, syncing on save
 https://hq.oikapi.com/crm
The part that feels like magic

Add a field. It's live on the api before you tab away.

The API isn't generated from your schema, it is your schema. Metadata-driven, so there's no client to regenerate and nothing to drift. Save the file; the endpoint changes with it.

oi dev · watching crm/
# edit tables/01_leads.json, add one field:
  { "name": "score", "type": "integer" }

# …save. no build, no migration, no redeploy.
 tables/01_leads.json   +1 field (score)
 published, live in ~120ms
the API already knows
$ oi api GET '/api/apps/crm/tables/leads/records/LEAD-000042'
{
  "number": "LEAD-000042",
  "status": "qualified",
  "score": null          // ← there instantly, typed
}

Full CRUD over REST on every table, typed responses, a real filter DSL, cursor pagination. API docs →

Not a backend you rent

An app is files you version in git.

Tables, rules, roles, and permissions are plain JSON and TypeScript on disk. oi pull the whole app to your machine, review a change in a PR, and ship a signed .oikapp. Self-host the server, export your data whenever you want. Nothing is trapped.

oi init · scaffold oi dev · watch & sync oi push/pull · disk ↔ server oi build · signed package
~/crm · git
# the whole app is JSON + TypeScript on disk
crm/
  oikapi.json
  tables/01_leads.json
  rules/lead_score.ts
  roles/  permissions/  form_views/

$ git commit -m "crm: score leads" && oi push crm
 2 tables · 1 rule · 3 grants  published
Sandboxed TypeScript

Logic runs inside the write.

Business rules are TypeScript in a locked-down sandbox with a real standard library, permission-checked reads, exact-decimal money, an SSRF-guarded fetch. Mutate the record in place; throw to roll the whole write back. No separate function service to deploy.

rules/apply-discount.ts · before_update · orders
// `record` is the row being written; mutate it in place.
const customer = get("customers", record.customer_id);   // permission-checked

const rate = customer.tier === "gold" ? "0.10" : "0.05";
record.discount = Decimal.mul(record.subtotal, rate);  // exact money, as strings

if (Decimal(record.total).greaterThan(customer.credit_limit)) {
  throw new Error("Credit limit exceeded");   // ← rolls back the write
}

triggers on create · update · delete · schedule · webhook · email, the sandbox reference →

Permissions on every read

Governed by construction.

Declare access once, a row-level predicate over $user, column masks, app scope. The same predicate runs whether the read comes from the REST API, a rule script, a rollup, search, or an AI agent. Denied by default, an integration you ship can't leak across apps or surface a masked column.

table grant 500 > per-record 300 > app grant 100 > deny 0 · permissions →

one predicate · every path
# grant on the "deals" table
row_filter: eq(owner, $user.id)

# enforced identically for:
GET /api/apps/crm/tables/deals/records   # REST
list("deals", { … })                     # a rule
rollup(deals.count)                       # a rollup
oikapi-mcp                                # an agent
MCP server · shipped

An agent is just another principal.

The shipped MCP server exposes the whole platform to your assistants, and an agent authenticates as a first-class principal under the same RBAC, row-level security, and audit as a person. Its authority is exactly its grants, with a budget and a kill-switch. No shadow API, no implicit elevation.

~/helpdesk · oikapi-mcp
$ oi mcp-login
 authorized, same account, same permissions

$ oikapi-mcp
 platform tools registered
  list_records · create_record · search · start_workflow …
  … scoped by the agent's capability profile

// an agent reads and writes only what its grants allow,
// audited like anyone.

Define a table. Ship the rest.

Install the CLI, log in, and have a table live over the API in a couple of minutes.

open API on every object · your data is never trapped, see pricing