The app runtime API
The app's own door: /api/apps/*, opened by the app's key.
Authorization: Bearer cak_…The key is printed once by cartbase app deploy (the first deploy) or by a
rotation, and lives in the environment where the app's server code runs,
CARTBASE_APP_<KEY>_KEY. It reaches this app's settings, secrets and record
types on this store, and nothing else. A member's token, a CLI token or a
session is refused here.
Every answer is JSON. Errors follow the platform's envelope:
{ error, code, details? }.
| Status | Code | When |
|---|---|---|
| 401 | unauthenticated |
No key, or a revoked one |
| 403 | app_disabled |
The merchant switched the app off |
| 403 | app_scope |
The record type belongs to another app |
| 404 | not_found |
A record type the manifest does not declare, or a record that is not this type's |
| 400 | invalid_data |
A record that does not match its fields; details.errors: [{key, code, message}] |
GET /api/apps/me
Who am I, on which store, with which settings.
{
"app": { "id": "app_…", "key": "store-locator", "name": "Store locator", "version": "1.0.0", "status": "live" },
"store": { "client_id": "…" },
"settings": { "maps_key": "AIza…", "default_zoom": 7 }, // secrets DECRYPTED, here only
"records": [
{ "type": "location", "store_type": "store-locator.location", "name": "Location", "visibility": "public", "fields": [ … ] }
]
}store_type is what the storefront asks the store API for.
GET /api/apps/records/:type
The app's records of one type. Query q, status (draft | active),
limit (default 50, up to 200), offset.
{ "records": [ { "id": "mobj_…", "handle": "ay-gross-mega", "display_name": "AY GROSS MEGA", "fields": { "city": "Пловдив", … }, "status": "active", … } ], "count": 40, "offset": 0, "limit": 50 }POST /api/apps/records/:type
Create a record. Body { handle?, display_name?, fields?, status? }. The
handle is derived from the display name when absent. required fields are
enforced when status is active. Answers 201 { record }.
GET /api/apps/records/:type/:id
One record with its fields resolved: { record, resolved_fields }.
POST /api/apps/records/:type/:id
Partial update, same body as create. The merged field set is validated, so
a patch cannot dodge a required field on activation. Answers { record }.
DELETE /api/apps/records/:type/:id
Answers { id, object: "record", deleted: true }.
The storefront's reads
Public record types answer to the publishable key at the store API, as any metaobject does:
GET /api/store/metaobjects/<key>.<type>
GET /api/store/metaobjects/<key>.<type>/<handle>Active records only; a private type is 404. The package wraps both:
listAppRecords and getAppRecord in @cartbase/storefront/api/apps.