inmake DOCS
Docs / API / Overview

Overview

Hosts, the three headers, error shape, batch paths, pagination, locales, credits.

The API is one Express application behind one HTTPS endpoint per environment. Every route is POST with a JSON body and a JSON response; there are no verbs to remember, only paths. This page is the part that is the same for every route — the reference pages in this section list the routes themselves, generated from the server's own route documentation.

Hosts#

Environment Base Example
Production https://core.inmake.dev/api POST https://core.inmake.dev/api/public/store
Demo https://demo-core.inmake.dev/api POST https://demo-core.inmake.dev/api/public/store

Two groups live beside /api instead of under it, on the same host: /system/** (the master-only control plane, https://core.inmake.dev/system/…) and /generative/** (the twin of /api/gen that bills the shared wallet). Each reference page prints the group's real base path.

GET on the base itself (https://core.inmake.dev/api, no token) returns the live spec: version, number, env, the header contract and every route — the same document these pages are generated from. The badges at the top of each group page come from it.

Headers#

Header Required Notes
access-token always A store access token — see Authentication.
identity-token per user A customer-bound token; alone it inherits its parent's access with the identity's customer, next to an access token only the customer is taken from it.
store preferred The store id. Falls back to store in the body; the header wins when both are present.
content-type always application/json.

Groups#

Group Base Who calls it
Auth /api/auth Anyone with a token — inspect what it may do.
Public /api/public Storefronts and browsers with a public token: read-only.
Admin /api/admin Servers with a private token: generic document/collection CRUD, uploads, analytics.
Process /api/process Carts, orders, payments, subscriptions.
Promo /api/promo Credits ledger and coupons.
Secure /api/secure Token and secret management (owner/master).
Gen /api/gen Metered generative endpoints, billed to the central wallet; identity-token only.
Mailing /api/mailing Send a store e-mail template over the store's SMTP.
Generative /generative The /api/gen twin (same wallet, same credential).
Hooks (outbound) — What the platform sends to you when data changes.
Hook (inbound) /hook Stripe webhooks — platform-side, shown for completeness.
System /system Master-only store and tenant control plane.

Access evaluation#

The middleware in front of every group looks up the token, matches the request path against the token's access tree segment by segment (public → store, admin → read, …), and either lets the handler run or answers 403. Stock paths get an extra ownership check. auth/* is always allowed so a token can always inspect itself. What a route needs is therefore not printed per route — it is the route's own path.

Errors#

{
  "error": "RequestError",
  "message": "Missing required parameter: path",
  "body": { "…": "your request body, credentials removed" }
}

400 bad parameters · 401 no valid token · 402 empty wallet on a paid route · 403 the access tree said no · 404 not found · 409 conflict · 500 internal (the message is the exception). Details in Authentication › Errors.

Batch paths#

Routes that take a path (admin/read, admin/update, …) also accept a list of paths; the evaluation runs per path and the response is a list in the same order. This is how the SDK's batch calls work.

Listing and pagination#

List routes share one shape: query (a set of conditions — a scalar value is an equality shorthand), order_by ({field, direction}), limit, offset (the id of the last document you received) and mask (return a subset of fields). Page by passing the last id back as offset.

Query keys#

Equality filters alone, or a range / order_by on one field with no filter, need nothing. A listing that filters and sorts — equality on some fields, then a range or an order_by on another — runs on a query key of the collection: built in for the common shapes (below), declared for the rest as keys: {"<name>": ["<field>", …]} on the collection row (the console's collection settings; for a module, the manifest's data.collections[].collection.keys). Rule of thumb: equality on the leading fields, range or sort on the last — {"status_prep_time": ["status", "prep_time"]} serves status == public ordered by prep_time in either direction, with an optional range on it. The platform maintains a computed _k.{name} field on every document (never write it; the public routes never return it) and rewrites a matching query onto it, so no composite index is involved. Limits: up to 8 keys per collection, 1–4 fields each, no id, no _k. A query no key serves still runs while its equality part matches at most 500 documents; above that the answer is 400 {"error": "query_key_required", "collection": …, "suggest": [fields]} — suggest is the field list to declare. With the built-in keys this only happens for a shape outside them.

Built-in keys#

Most listings need nothing declared. Every content collection gets keys derived from its schema template (schema order decides "first"; up to 5, on their own budget — the 8 explicit keys are untouched):

Built-in key Fields Serves
status_timestamp [status, timestamp] "public X, newest first" — every collection, with or without a template
status_{d} [status, d] for the first two datetime fields d "public articles by publish_date", date ranges
{e}_{d1} [e, d1] for the first enum field e; d1 = the first datetime field, else timestamp "category X, newest first"
status_{e}_{d1} [status, e, d1] the same, public only

So a recipes collection with an enum category and no date field has status_timestamp, category_timestamp and status_category_timestamp; articles with a publish_date has status_timestamp and status_publish_date. Nothing is derived for number, boolean or array fields — a "by prep_time" listing declares its own key.

The products mirror (data/{locale}/products, what a storefront lists) has a fixed set, and its array filters run on platform composite indexes instead:

Products Shape Serves
status_price [status, price.price] public products by price, either direction
status_name [status, name] public products A–Z
status_timestamp [status, timestamp] public products, newest
16 composites categories / tags array-contains × sort by price.price asc, price.price desc, name asc, timestamp desc — each plain and with status == public category and tag pages; array-contains-any (a multi-select) uses the same index

One array filter per query: "category X and tag Y" is not one index — filter the second array in memory over the category page, or add a scalar field and a key. The mirror carries status and timestamp from the root product, so a product never opened in the content editor is listable too.

A built-in is disabled with keys: {"<name>": null} and overridden by declaring the same name. Built-ins backfill lazily — the first listing after they appear starts the build (building → ready; the query runs natively meanwhile).

→ the full list, generated from the index file: Indexes

Locales#

Content, slugs, templates and translations are per locale in the xx_YY form (cs_CZ). A locale the store does not declare is a 400.

Credits#

The gen/* and generative/* routes are metered; each shows its price in credits next to the path. 1 credit = $0.01 by convention. See Credits.