Alloovium

Capabilities

Workflows

Run user-defined multi-step automations over the vault. Workflows are authored in the dashboard and triggered from your backend via the public API.

Lifecycle

Every workflow run follows the same pattern:

  1. Call capability with the workflow ID and optional inputs.
  2. Get back a field. The run starts in state state.
  3. Poll capability every 2–5 seconds.
  4. Run states transition: states.
  5. When condition, the field field contains the result.

Authoring is dashboard-only

The public API does not expose workflow creation or editing. Build the workflow once in the dashboard, copy its ID, then run it from code.

workflows.list

GET/api/v2/workflows

List workflows available to the API key's user.

scope: workflows:readcost: 1

Request

bash
curl -sS "https://api.alloovium.com/api/v2/workflows?limit=25" \ -H "Authorization: Bearer $ALLOOVIUM_API_KEY"

Response

json
{ "data": [ { "id": "wf_1f02d9ef-...", "name": "Weekly submittal review", "description": "Scan new submittals for noncompliance and summarise.", "enabled": true, "trigger_type": "manual", "created_at": "2026-03-12T08:00:00+00:00", "updated_at": "2026-04-01T12:14:00+00:00" } ], "next_cursor": null, "has_more": false }

workflows.run

POST/api/v2/workflows/{workflow_id}/runs

Kick off a new run of a workflow. Returns a run_id you poll for status.

scope: workflows:writecost: 25

Request body

json
{ "inputs": { "start_date": "2026-04-01", "end_date": "2026-04-08" }, "project_id": "8f2e3c1a-..." }
  • field — optional map of the workflow's declared input variables.
  • field — optional scope. Required for workflows that reference block blocks.
bash
curl -sS https://api.alloovium.com/api/v2/workflows/wf_1f02d9ef-.../runs \ -H "Authorization: Bearer $ALLOOVIUM_API_KEY" \ -H "Idempotency-Key: weekly-review-2026-04-08" \ -H "Content-Type: application/json" \ -d '{ "inputs": {"start_date": "2026-04-01", "end_date": "2026-04-08"}, "project_id": "8f2e3c1a-..." }'

Response

json
{ "run_id": "run_c1d2e3f4-...", "workflow_id": "wf_1f02d9ef-...", "status": "pending", "started_at": null }

Attach an Idempotency-Key

Workflow runs cost 25 tokens and produce side effects. An idempotency key ensures a dropped response does not kick off the same run twice — see Idempotency.

workflows.get_run_status

GET/api/v2/workflows/runs/{run_id}

Poll a run's progress, stage, outputs, and error state.

scope: workflows:readcost: 1

Response (running)

json
{ "run_id": "run_c1d2e3f4-...", "workflow_id": "wf_1f02d9ef-...", "status": "running", "progress": 42, "stage": "Analysing submittals", "inputs": {"start_date": "2026-04-01", "end_date": "2026-04-08"}, "outputs": null, "error_message": null, "started_at": "2026-04-08T10:12:05+00:00", "completed_at": null, "created_at": "2026-04-08T10:12:00+00:00" }

Response (completed)

json
{ "run_id": "run_c1d2e3f4-...", "workflow_id": "wf_1f02d9ef-...", "status": "completed", "progress": 100, "stage": "done", "inputs": {"start_date": "2026-04-01", "end_date": "2026-04-08"}, "outputs": { "summary": "5 submittals reviewed, 2 flagged for non-compliance.", "items": [ {"document_id": "4a1c2b3d-...", "status": "non-compliant", "reason": "..."} ] }, "error_message": null, "started_at": "2026-04-08T10:12:05+00:00", "completed_at": "2026-04-08T10:14:18+00:00", "created_at": "2026-04-08T10:12:00+00:00" }

Status states

StatusTerminal?Notes
pendingnoQueued; not yet claimed by a worker.
runningnoCurrently executing. progress + stage update as it runs.
completedyesFinished successfully. outputs is populated.
failedyesRuntime error. error_message contains a human-readable reason.
cancelledyesCancelled by the user or by a timeout. outputs may be null or partial.

Polling pattern

python
import time, httpx def wait_for_run(run_id: str, api_key: str, timeout_s: int = 900): url = f"https://api.alloovium.com/api/v2/workflows/runs/{run_id}" headers = {"Authorization": f"Bearer {api_key}"} deadline = time.monotonic() + timeout_s while time.monotonic() < deadline: resp = httpx.get(url, headers=headers) resp.raise_for_status() payload = resp.json() status = payload["status"] if status in ("completed", "failed", "cancelled"): return payload time.sleep(3) # 2-5s polling is ideal raise TimeoutError(f"run {run_id} did not finish in {timeout_s}s")

Do not tight-loop

Polling costs 1 token per call. A 3-second loop on a 10-minute run costs ~200 tokens; a 50ms tight loop would blow your bucket in seconds and earn you a 429.

See also

  • Templates — document-fill jobs use the same pending/polling pattern.
  • Idempotency — never kick off the same run twice.