---
summary: "Every endpoint exposed by the ScaiCore wrapper module \u2014 Cores, checkpoints,\
  \ plugins, debug, events, delegation, API exposure."
title: API reference
path: modules/scaicore/reference/api
status: published
---

All endpoints are mounted at `/v1/modules/scaicore/` and authenticate with the standard ScaiGrid bearer token. Responses use ScaiGrid's standard envelope (`{ "data": ... }` for success, `{ "error": ... }` for failures).

This wrapper hosts ScaiCore programs. The IR and language internals are documented separately at [/docs/scaicore](https://www.scailabs.ai/docs/scaicore).

## Cores

### `POST /cores`

Create a Core in the caller's tenant.

| Field | Required | Notes |
|---|---|---|
| `name` | yes | Human-readable name. Slug is auto-generated and must be unique within tenant. |
| `runtime_mode` | no | `event_driven` (default), `interactive`, `api`, `model`. |
| `concurrency_mode` | no | `stateless` (default), `entity`, `singleton`. |
| `entity_key_field` | no | Required when `concurrency_mode = entity`. |
| `source` | no | The IR dict from `parse-bundle`. Defaults to `{}`. |
| `plugins` | no | List of plugin configs. Defaults to `[]`. |
| `environment` | no | Env-var dict. Values typed `secret` are encrypted at rest. |
| `resource_limits` | no | Free-form JSON. |
| `checkpoint_mode` | no | `auto` (default), `visual_queue`, `routed`. |
| `privilege_level` | no | `standard` (default), `elevated`, `admin`. |
| `metadata` | no | Free-form JSON; `metadata.skills` triggers auto-binding on start. |
| `avatar_b64`, `avatar_content_type` | no | Inline avatar; uploaded to S3 on create. |

Returns `201 Created` with the new Core.

### `POST /cores/parse-bundle`

Parse a `.scaicore-ir` bundle or a JSON IR dict.

- Multipart form with `file` field.
- Bundles capped at 10 MB.
- Binary bundles must start with the `SCIR` magic.
- Returns `{source, summary}` where `summary` includes name, version, schema_version, flow names, model names, identity name/persona, flags for triggers/plugins, and any embedded avatar.

### `GET /cores`

List the caller's tenant's Cores. Cursor-paginated (`limit`, `cursor` query params).

### `GET /cores/{core_id}`

Fetch one Core's full config. Tenant-scoped; 404 if not in the caller's tenant.

### `PUT /cores/{core_id}`

Replace editable fields: `name`, `runtime_mode`, `source`, `concurrency_mode`, `privilege_level`, `plugins`, `environment`, `resource_limits`, `checkpoint_mode`, `metadata`. Slug, tenant, identity columns are immutable here.

### `DELETE /cores/{core_id}`

Hard-delete the Core. Unregisters its engine from the in-process registry first.

### Lifecycle transitions

| Endpoint | What it does | Legal `from` |
|---|---|---|
| `POST /cores/{id}/start` | Validate, resolve env + identity + skills, transition `starting` then `running`. | `created`, `configuring`, `stopped`, `error` |
| `POST /cores/{id}/stop` | Unregister engine, transition `stopping` then `stopped`. | `running` |
| `POST /cores/{id}/restart` | Stop if running, then start. | any |
| `POST /cores/{id}/pause` | Transition to `paused`. | `running` |
| `POST /cores/{id}/resume` | Transition back to `running`. | `paused`, `suspended` |

Invalid transitions raise `INVALID_CORE_TRANSITION` (409).

### Publish / unpublish

#### `POST /cores/{core_id}/publish`

Publish the Core as a `FrontendModel` in ScaiGrid's catalogue. Body (optional):

```json
{ "group_ids": ["mg_xxx", "mg_yyy"] }
```

Non-super-admins cannot add to `global` groups or to partner/tenant groups outside their scope; out-of-scope groups are silently dropped. Errors with `VALIDATION_ERROR` if already published.

#### `POST /cores/{core_id}/unpublish`

Remove the FrontendModel + BackendModel + group memberships. Errors with `VALIDATION_ERROR` if not currently published.

### Avatar

#### `POST /cores/{core_id}/avatar`

Multipart upload. PNG / JPEG / GIF / WebP / SVG; 2 MB max. Magic-byte validation rejects mismatched content. Stored at `scaicore/{tenant_id}/{core_id}/avatar` in S3; the Core's `avatar_url` is set to the proxy path.

#### `GET /cores/{core_id}/avatar`

Public, unauthenticated. Streams the avatar bytes with a 1-hour cache header. Returns 404 if no avatar is set.

## Checkpoints

### `GET /checkpoints`

List pending checkpoints the caller can act on (assigned to them, their groups, or roles they hold). Cursor-paginated.

### `GET /checkpoints/all`

List every checkpoint in the tenant. Tenant-admin scope.

### `GET /checkpoints/{checkpoint_id}`

Fetch one checkpoint's full payload, including parsed assignee, options, context, and resolution (if any).

### `POST /checkpoints/{checkpoint_id}/resolve`

| Field | Notes |
|---|---|
| `decision` | Required. Free-form string (the program decides what's valid). |
| `response_data` | Optional JSON; surfaces back to the program. |
| `comment` | Optional human note. |

Errors with `CHECKPOINT_ALREADY_RESOLVED` (409) if status is not `pending`.

### `POST /checkpoints/{checkpoint_id}/cancel`

Cancel without a decision. Status flips to `cancelled`; the runtime never resumes from this row.

### `POST /checkpoints/{checkpoint_id}/reassign`

```json
{ "assignee": "user:alice@acme", "comment": "..." }
```

Parses the assignee, rewrites `assignee_raw`/`assignee_type`/`assignee_resolved`, re-fires the notifier.

### `GET /checkpoints/{checkpoint_id}/history`

Compact event list — created, notification sent, resolved. For full audit, query ScaiGrid's `/v1/audit/events?module=scaicore`.

## Plugins

### `GET /cores/{core_id}/plugins`

List the Core's installed plugin entries.

### `POST /cores/{core_id}/plugins`

Install a plugin entry. Body:

```json
{ "alias": "my-plugin", "endpoint": "https://...", "config": {} }
```

Stored as a JSON entry in the Core's `plugins` list.

### `PUT /cores/{core_id}/plugins/{plugin_alias}`

Replace one plugin entry's config.

### `DELETE /cores/{core_id}/plugins/{plugin_alias}`

Remove the entry.

### `GET /plugins/available`

**Not yet implemented** — currently returns `{ "items": [] }`. A plugin marketplace listing is planned but not built.

## Debug

### `GET /cores/{core_id}/logs`

**Stub** — returns `{ "logs": [], "message": "Log retrieval placeholder" }`. Persistent log retrieval is not yet wired.

### `GET /cores/{core_id}/logs/stream`

**Not yet implemented** — returns `501` with code `NOT_IMPLEMENTED`. SSE log streaming is planned.

### `GET /cores/{core_id}/state`

Returns `{core_id, status, runtime_mode, concurrency_mode}` — the persisted runtime descriptors. Not a live snapshot of the engine.

### `POST /cores/{core_id}/debug/breakpoint`

**Not yet implemented** — `501`.

### `POST /cores/{core_id}/debug/step`

**Not yet implemented** — `501`.

### `POST /cores/{core_id}/debug/inspect`

**Not yet implemented** — `501`.

## Events and triggers

### `POST /cores/{core_id}/events`

Send a named event to the Core. Body: `{ "event_name": "...", "data": {} }`. Today the call records the dispatch as `accepted`; the eventing pipeline is wired through the HostEnvironment's EventBus.

### `GET /cores/{core_id}/events/history`

**Not yet implemented** — currently returns `{ "events": [] }`. Querying `scaicore.runtime.*` events from the EventBus is on the roadmap.

### `POST /cores/{core_id}/triggers`

Register a trigger entry. Body:

```json
{ "event_type": "purchase.request", "flow": "approval", "config": {} }
```

Triggers are stored on the Core's `environment.triggers` JSON list.

### `GET /cores/{core_id}/triggers`

List the Core's triggers.

### `DELETE /cores/{core_id}/triggers/{trigger_id}`

Remove a trigger by its UUID.

## Delegation

### `POST /cores/{core_id}/delegate`

Delegate a human user's identity to the Core. Body:

```json
{ "user_id": "usr_...", "scopes": ["models:use", "files:read"], "expires_at": "2026-12-31T00:00:00Z" }
```

Requires at least one scope. Flips `identity_mode` to `user_delegated`, records the granting user, optional expiry.

### `GET /cores/{core_id}/delegation`

Returns `{identity_mode, delegated_user_id, delegation_scopes, delegation_expires_at, delegation_granted_by}`.

### `PUT /cores/{core_id}/delegation`

Update `scopes` and/or `expires_at` on an existing delegation. Errors with `DELEGATION_VALIDATION_ERROR` if the Core isn't delegated.

### `POST /cores/{core_id}/revoke-delegation`

Flips `identity_mode` back to `service_account` and clears all delegation columns.

## API exposure (per-Core programmatic API)

### `GET /cores/{core_id}/api/spec`

Returns a compact spec listing the Core's flow names + descriptions, derived from the IR `source.flows`.

### `* /cores/{core_id}/api/invoke/{path}`

**Not yet implemented** — returns `501`. Calling Core-defined API paths from outside is on the roadmap.

## Conversation logs

There is no `/conversations/...` endpoint on this module today. Querying conversations against published Cores is planned but not yet implemented — until then, use the standard ScaiGrid inference accounting / audit pipeline.

## Errors

All endpoints use ScaiGrid's standard error envelope. ScaiCore-specific codes:

| Code | HTTP | Meaning |
|---|---|---|
| `CORE_NOT_FOUND` | 404 | Core id doesn't exist in the caller's tenant. |
| `INVALID_CORE_TRANSITION` | 409 | Lifecycle transition isn't legal from current status. |
| `CHECKPOINT_NOT_FOUND` | 404 | Checkpoint id missing or not in this tenant. |
| `CHECKPOINT_ALREADY_RESOLVED` | 409 | Status is not `pending`. |
| `DELEGATION_NOT_ACTIVE` | 403 | Core does not have an active user delegation. |
| `DELEGATED_USER_NOT_FOUND` | 403 | Delegated user is missing or inactive. |
| `DELEGATION_VALIDATION_ERROR` | 400 | Delegation body failed validation (e.g. empty scopes). |
| `DELEGATION_EXPIRED` | 403 | Delegation's `expires_at` is in the past. |
| `INVALID_FILE_TYPE` | 400 | Avatar upload rejected on content-type or magic bytes. |
| `FILE_TOO_LARGE` | 400 | Avatar over 2 MB (or bundle over 10 MB). |
| `STORAGE_ERROR` | 502 | S3 put/get failed. |
| `NO_AVATAR` | 404 | Core has no avatar set. |
| `NOT_IMPLEMENTED` | 501 | Stub endpoint (log stream, debug breakpoint/step/inspect, API invoke, plugin marketplace listing, event history). |

For the `INVALID_SOURCE_IR` and IR-validation codes raised on start, see the ScaiCore language docs at [/docs/scaicore](https://www.scailabs.ai/docs/scaicore).
