Technical docs
Private API
Overview
Support reference for the organization-scoped private API under `/api/private`.
Auth
- Current auth is the raw organization private API key in the `api-key` header.
- Current middleware does not accept `Authorization: Bearer <token>`.
- Example:
```bash curl -H "api-key: <TOKEN>" "https://api.alloy.cx/api/private/storage/" ```
Current route groups
- `/api/private/storage`
- `/api/private/trigger`
- `/api/private/stargate`
Storage routes
Base URL: `{api_url}/api/private/storage`
These routes expose full organization storage access.
| Method | Path | Query / Body | Notes |
|---|---|---|---|
| `GET` | `/` | `?path=` optional | Lists direct children of a folder. `path` defaults to `/`. Returns `404` when the folder does not exist or the path resolves to a file. |
| `POST` | `/upload` | `multipart/form-data` with optional `path` and required `file` part | Max file size is `10 MB`. The stored filename comes from the uploaded file's original filename. Omitting `path` uploads to storage root. Existing files are overwritten. |
| `GET` | `/meta` | `?path=` required | File-only metadata lookup. Returns `path`, `name`, `size`, `created_at`, `modified_at`, `hash`, and `mime_type`. Returns `400` when the path is a folder and `404` when the file is missing. |
| `DELETE` | `/file` | `?path=` required | Deletes a file or folder. Returns `400` for root deletion attempts. |
| `GET` | `/download` | `?path=` required | File-only download. Returns `400` when the path is a folder. |
| `POST` | `/folder` | JSON `{ name, path? }` | Creates a folder and returns its canonical relative path. |
| `POST` | `/rename` | JSON `{ path, new_name }` | Renames a file or folder in place. |
| `POST` | `/move` | JSON `{ source_path, dest_path }` | Moves a file or folder into the destination directory. `dest_path` is a directory path, not a full target filename. |
Storage response notes
- Successful storage mutations return `success: true` and usually a `data.path` field with the canonical relative path.
- Upload validation failures return `400`.
- Uploads above `10 MB` return `413`.
- Upload has no replace/skip flag. If the target file already exists, the server truncates and rewrites it, returns `200`, and emits `storage_file.updated`.
- Upload has no conflict status for existing files, no ETag / `If-Match` precondition, and no optimistic concurrency control. Clients should treat duplicate uploads as last-write-wins.
- `GET /storage/meta` prefers a cached document hash when one already exists in `organization_documents.file_hash`; otherwise it computes the hash from the current file contents on demand.
- `POST /storage/rename` and `POST /storage/move` return `409` on target-path conflicts.
- The current private storage API does not expose `copy`, `stats`, or folder-sharing endpoints.
Trigger route
Base URL: `{api_url}/api/private/trigger`
| Method | Path | Body | Notes |
|---|---|---|---|
| `POST` | `/{workflow_id}` | Arbitrary JSON payload | Starts the workflow from its configured starting step and returns the created run ID plus the immediate queue result. |
Trigger response notes
- Returns `404` when the workflow does not exist in the authenticated organization.
- Returns `404` when the workflow exists but has no `flow` or no `starting_step_id`.
- On success returns:
- `success: true`
- `data.runId`
- `data.result`
Stargate routes
Base URL: `{api_url}/api/private/stargate`
Stargate lets a gateway process poll Alloy for work routed to a named internal system, execute it against that internal system, and report the result back to Alloy. For the architecture and setup model, see `stargate.md`.
| Method | Path | Query / Body | Notes |
|---|---|---|---|
| `GET` | `/` | `?system=` required | Long-polls for up to `60` seconds for pending tasks for the named internal system. Returns early when tasks are available; otherwise returns `success: true, data: []`. |
| `POST` | `/{task_id}` | Any request body | Records the posted body as the task response and flips the task from `requested` to `responded`. The current public Stargate gateway posts a JSON envelope with `ok`, `status`, `body`, and optional `error`, but the Alloy route itself does not enforce a response schema. |
Stargate response notes
- The gateway uses the same `api-key` authentication as the rest of the private API.
- `system` is a routing key. A gateway should only receive tasks for the internal system name it passes in the poll request.
- Returned tasks include `stargate_task_id`, `organization_id`, `system`, `method`, `uri`, `body`, `response`, `status`, `created_at`, and `updated_at`.
- Task statuses currently move through `created`, `requested`, `responded`, `completed`, or `failed`.
- The `GET` route checks for new work every `5` seconds during the long-poll window.
- The `POST` route currently accepts JSON, plain text, raw bytes, or empty bodies and stores the payload as text.
- `POST /{task_id}` returns `404` when the task is missing.
- `POST /{task_id}` returns `400` when the task is not currently in `requested` status.