Technical docs

Private API

Overview

Support reference for the organization-scoped private API under `/api/private`.

Auth

  • Current auth is the organization private API key.
  • The middleware accepts either `Authorization: Bearer <token>` or the raw key in the `api-key` header.
  • Example:

```bash curl -H "Authorization: Bearer <TOKEN>" "https://api.alloy.cx/api/private/storage/" ```

Organization status and API access

When an organization's `status` is `inactive`, the private API blocks all mutating methods:

  • `POST`, `PUT`, `PATCH`, and `DELETE` return `403` with `{ error: "Organization is inactive", code: "ORGANIZATION_INACTIVE" }`.
  • Side-effecting `GET` endpoints (e.g. `GET /api/private/stargate/?system=...`) are also blocked.
  • Read-only `GET` endpoints (storage listing, metadata, downloads) continue to work.

Current route groups

  • `/api/private/storage`
  • `/api/private/trigger`
  • `/api/private/stargate`
  • `/api/private/employee`

Storage routes

Base URL: `{api_url}/api/private/storage`

These routes expose full organization storage access.

MethodPathQuery / BodyNotes
`GET``/``?path=` optionalLists 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` partMax 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=` requiredFile-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=` requiredDeletes a file or folder. Returns `400` for root deletion attempts.
`GET``/download``?path=` requiredFile-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`

MethodPathBodyNotes
`POST``/{workflow_id}`Arbitrary JSON payloadStarts 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`

Employee message routes

Base URL: `{api_url}/api/private/employee`

These routes let a server-side integration connect a custom chat system to an Alloy AI teammate. For the full external developer guide, see `references/custom-channel-integration.md`.

MethodPathQuery / BodyNotes
`POST``/{employee_id}/messages`JSON body with required `message` and `channel`; optional all-or-nothing `conversation` and `contact`; optional `attachments[]` with base64 file dataSends one user message to an AI teammate and returns the AI response. With `conversation` and `contact`, the chat is saved and can continue later. Without them, the request is one-off and no chat history is saved.
`GET``/{employee_id}/messages``conversation_id`, `channel`, optional `page`, optional `limit` up to `50`Lists saved messages for a custom chat conversation. Use the same `channel` and `conversation_id` values that were used when sending messages.

Employee message response notes

  • `POST /employee/{employee_id}/messages` returns `success: true`, `data.runId`, `data.message`, and `data.messageId`.
  • `data.messageId` is `null` for one-off requests where `conversation` and `contact` are omitted.
  • `POST` returns `404` when the AI teammate does not exist in the authenticated organization.
  • `POST` returns `422` when the AI teammate is not ready to process messages.
  • `GET` returns message objects plus pagination metadata.
  • `GET` returns `404` when no saved chat exists for the supplied `channel` and `conversation_id`.

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`.

MethodPathQuery / BodyNotes
`GET``/``?system=` requiredLong-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 bodyRecords 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.

Start building your AI team