Initial marketplace with flamenco and kitsu plugins

Bundles the flamenco-api and kitsu-api skills as Claude Code plugins
under an "adm-tools" marketplace.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Joseph HENRY 2026-05-07 17:13:13 +02:00
commit 3600c870cd
10 changed files with 2812 additions and 0 deletions

View File

@ -0,0 +1,22 @@
{
"name": "adm-tools",
"owner": {
"name": "Autour de Minuit",
"email": "adv.bdl.dev@gmail.com"
},
"description": "Claude Code plugins for the ADM Blender pipeline and production tracking",
"plugins": [
{
"name": "flamenco",
"source": "./plugins/flamenco",
"description": "Flamenco render farm tools and references",
"version": "1.0.0"
},
{
"name": "kitsu",
"source": "./plugins/kitsu",
"description": "Kitsu production tracking tools and references",
"version": "1.0.0"
}
]
}

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.DS_Store
*.swp
*.swo
__pycache__/
.venv/

41
README.md Normal file
View File

@ -0,0 +1,41 @@
# ADM Tools — Claude Code Marketplace
Claude Code plugins for Autour de Minuit's Blender pipeline and production tracking.
## Plugins
- **flamenco** — Flamenco render farm tools. Currently bundles the `flamenco-api` skill (API reference, configuration, worker/job management).
- **kitsu** — Kitsu production tracking tools. Currently bundles the `kitsu-api` skill (Zou REST API and gazu SDK reference).
## Install
```
/plugin marketplace add https://git.autourdeminuit.com/autour_de_minuit/claude-plugins.git
/plugin install flamenco@adm-tools
/plugin install kitsu@adm-tools
```
Once installed, the skills auto-trigger on relevant prompts. Namespaced names are `flamenco:flamenco-api` and `kitsu:kitsu-api`.
## Updating
After a new version is pushed:
```
/plugin marketplace update adm-tools
```
## Layout
```
.claude-plugin/marketplace.json — marketplace catalog
plugins/<plugin>/.claude-plugin/ — per-plugin manifest
plugins/<plugin>/skills/<skill>/ — bundled skill (SKILL.md + references)
```
## Releasing changes
1. Edit the skill content under `plugins/<plugin>/skills/<skill>/`.
2. Bump the `version` in both `plugins/<plugin>/.claude-plugin/plugin.json` and the matching entry in `.claude-plugin/marketplace.json`.
3. Commit and push.
4. Tell teammates to run `/plugin marketplace update adm-tools`.

View File

@ -0,0 +1,8 @@
{
"name": "flamenco",
"description": "Flamenco render farm tools and references",
"version": "1.0.0",
"author": {
"name": "Autour de Minuit"
}
}

View File

@ -0,0 +1,189 @@
---
name: flamenco-api
description: >
Flamenco render farm manager API reference, configuration, and usage guide.
Use this skill whenever working with Flamenco — querying jobs, workers, tasks, or farm status via
the REST API, writing curl commands or Python scripts that talk to the Flamenco Manager,
configuring the manager or workers, troubleshooting render farm issues, managing worker tags
or sleep schedules, creating custom job types, or understanding how Flamenco integrates with
Blender. Also use when the user mentions render farm, farm status, render workers, job submission,
or Flamenco in any context. Trigger on mentions of flamenco, render farm, render worker,
farm status, job queue, render job, or worker management in the context of rendering.
---
# Flamenco Render Farm
[Flamenco](https://flamenco.blender.org/) is the render farm manager developed by the Blender
Foundation. It consists of a **Manager** (HTTP server, web UI, REST API) and one or more
**Workers** that pull jobs from the Manager and execute them — usually Blender renders, but the
job-type system is generic enough for ffmpeg encodes, file copies, or anything else.
## Setup before answering
Flamenco is self-hosted, so the Manager URL is site-specific. Before constructing API calls:
1. Check the user's environment for a Manager URL (env var like `FLAMENCO_MANAGER_URL`,
project config, or `CLAUDE.md`). The Manager web UI and the REST API share the same host;
`/api/v3/` is the API prefix.
2. If you can't find one, ask the user. Don't invent a URL.
In examples below, `<MANAGER_URL>` is a placeholder for the user's Manager root
(e.g. `https://flamenco.example.com` or `http://localhost:8080`). The API base is
`<MANAGER_URL>/api/v3/`.
Useful endpoints on any Manager:
- Web UI: `<MANAGER_URL>/`
- Swagger UI: `<MANAGER_URL>/api/v3/swagger-ui/`
- OpenAPI spec: `<MANAGER_URL>/api/v3/openapi3.json`
The API has no authentication by default — Flamenco assumes a trusted LAN. If the user has
fronted it with a reverse proxy that adds auth, account for that.
## Quick API examples
```bash
# Farm status (one of: active, idle, waiting, asleep, inoperative, unknown, starting)
curl -s <MANAGER_URL>/api/v3/status
# Manager version
curl -s <MANAGER_URL>/api/v3/version
# List all workers
curl -s <MANAGER_URL>/api/v3/worker-mgt/workers
# List all jobs
curl -s <MANAGER_URL>/api/v3/jobs
# Get a specific job
curl -s <MANAGER_URL>/api/v3/jobs/{job_id}
# Get tasks for a job
curl -s <MANAGER_URL>/api/v3/jobs/{job_id}/tasks
# Get task details (commands, status, assigned worker)
curl -s <MANAGER_URL>/api/v3/tasks/{task_id}
# Tail a task's log as plain text
curl -s <MANAGER_URL>/api/v3/tasks/{task_id}/logtail
# Query jobs by status (note: jobs query is POST, not GET)
curl -s <MANAGER_URL>/api/v3/jobs \
-X POST -H 'Content-Type: application/json' \
-d '{"status_in": ["failed"], "order_by": ["updated_at"], "limit": 5}'
# Change worker status (awake, asleep, offline, restart) — is_lazy waits for current task
curl -X POST <MANAGER_URL>/api/v3/worker-mgt/workers/{worker_id}/setstatus \
-H 'Content-Type: application/json' -d '{"status": "awake", "is_lazy": false}'
# Cancel / pause / requeue a job
curl -X POST <MANAGER_URL>/api/v3/jobs/{job_id}/setstatus \
-H 'Content-Type: application/json' -d '{"status": "canceled", "reason": "no longer needed"}'
```
## Key concepts
- **Job**: A render request, typically submitted from the Blender add-on. Carries settings
(blend file, frame range, output path, format) and is compiled by the Manager into tasks.
- **Task**: An executable unit within a job (e.g. "render frames 110"). Assigned to one worker
at a time. A task contains one or more **commands**.
- **Command**: The lowest-level operation a worker runs (e.g. `blender-render`, `move-directory`,
`frames-to-video`). Defined by the worker code; referenced by job-type scripts.
- **Worker**: A machine that polls the Manager for tasks and executes them. Has a status
(awake, asleep, offline, error, …) and a list of supported task types.
- **Tag**: A grouping label for workers. Jobs can be restricted to a tag so they only run on
matching workers (e.g. a `gpu` tag for GPU-only nodes).
- **Job type**: A JavaScript file in the Manager's `scripts/` directory that defines settings
and the compile function (turns a submitted job into a sequence of tasks). Built-in types
like `simple-blender-render` cover the common cases; custom types add new behaviors.
- **Shaman**: Optional content-addressed file store. When enabled, files are uploaded by
SHA256+size and symlinked into per-job checkout dirs. When disabled, files are referenced
in place on shared storage.
## Status enums
- **Job**: `active`, `canceled`, `completed`, `failed`, `paused`, `pause-requested`, `queued`,
`cancel-requested`, `requeueing`, `under-construction`
- **Task**: `active`, `canceled`, `completed`, `failed`, `queued`, `soft-failed`, `paused`
- **Worker**: `starting`, `awake`, `asleep`, `error`, `testing`, `offline`, `restart`
- **Farm**: `active`, `idle`, `waiting`, `asleep`, `inoperative`, `unknown`, `starting`
## Python SDK
Flamenco ships an auto-generated Python client (`flamenco-manager` on PyPI, importable as
`flamenco.manager`):
```python
from flamenco.manager import ApiClient, Configuration
from flamenco.manager.api import JobsApi, WorkerMgtApi, MetaApi
configuration = Configuration(host="<MANAGER_URL>")
api_client = ApiClient(configuration)
meta_api = MetaApi(api_client)
print(meta_api.get_version()) # FlamencoVersion
jobs_api = JobsApi(api_client)
jobs = jobs_api.fetch_jobs()
failed = [j for j in jobs.jobs if j.status == "failed"]
worker_api = WorkerMgtApi(api_client)
for w in worker_api.fetch_workers().workers:
print(f"{w.name}: {w.status}")
```
For ad-hoc scripts, plain `requests` against the REST API is often simpler and avoids the SDK
dependency.
## Submitting a job
Two endpoints take the same body — `POST /api/v3/jobs/check` validates without inserting,
`POST /api/v3/jobs` actually submits. Always send `submitter_platform` (`linux`, `windows`,
`darwin`, or `manager`) so the Manager can apply path replacements.
```bash
curl -X POST <MANAGER_URL>/api/v3/jobs \
-H 'Content-Type: application/json' \
-d '{
"name": "Test render",
"type": "simple-blender-render",
"priority": 50,
"submitter_platform": "linux",
"settings": {
"blendfile": "/render/scene.blend",
"frames": "1-100",
"chunk_size": 5,
"render_output_path": "/render/output/######",
"format": "PNG"
},
"metadata": {"project": "demo", "user.name": "artist"}
}'
```
The exact `settings` keys depend on the job type. List available types with
`GET /api/v3/jobs/types`, or fetch one with `GET /api/v3/jobs/type/{typeName}` to see its
declared settings.
## Reference files
For complete details, read these as needed — they're verbose and only worth loading when
you're actually constructing API calls or troubleshooting:
- **`references/api-reference.md`**: Every endpoint with parameters, request/response schemas,
status codes, and curl examples. Read this when constructing a specific API call or
understanding a response shape.
- **`references/usage-docs.md`** (optional, may not be present): General Flamenco usage —
shared storage, manager/worker configuration, two-way variable replacement, custom job
types, failure handling, troubleshooting. Read this for setup or non-API questions.
If a reference file is missing or out of date, the canonical source is
`<MANAGER_URL>/api/v3/swagger-ui/` and `<MANAGER_URL>/api/v3/openapi3.json` — fetching the
OpenAPI JSON is the fastest way to verify a schema.
## Notes on the worker-side API
`/api/v3/worker/*` endpoints (`sign-on`, `sign-off`, `register-worker`, `state`,
`state-changed`, `task`, `task/{id}`, `task/{id}/may-i-run`, `task/{id}/output-produced`)
exist for the worker process to talk back to the Manager. They are not normally called by
end-user scripts; only touch them if you're implementing a custom worker or debugging the
worker protocol.

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,8 @@
{
"name": "kitsu",
"description": "Kitsu production tracking tools and references",
"version": "1.0.0",
"author": {
"name": "Autour de Minuit"
}
}

View File

@ -0,0 +1,381 @@
---
name: kitsu-api
description: >
Comprehensive reference for the Kitsu production tracking API (Zou backend) and the gazu Python SDK.
Use this skill whenever working with Kitsu, gazu, CGWire, or production tracking API calls —
whether writing new integrations, debugging API issues, building pipeline tools that talk to Kitsu,
or understanding how the ADM Gadget pipeline interacts with the tracker. Also use when the user
mentions tasks, shots, assets, comments, previews, playlists, or casting in the context of
production tracking. Covers both the REST API (493 endpoints) and the gazu Python wrapper.
---
# Kitsu API & gazu SDK Reference
Kitsu is an open-source production tracking tool for animation/VFX studios, built by CGWire. The backend is called **Zou** and exposes a REST API. **gazu** is the official Python client SDK that wraps this API.
## Quick Reference
- **API docs**: https://api-docs.kitsu.cloud/
- **OpenAPI spec**: https://api-docs.kitsu.cloud/source.json
- **Developer guides**: https://dev.kitsu.cloud/
- **gazu docs**: https://gazu.cg-wire.com/
- **Zou source**: https://github.com/cgwire/zou
- **gazu source**: https://github.com/cgwire/gazu
## Authentication
### User Login (email/password → JWT)
```python
import gazu
gazu.set_host("https://kitsu.mystudio.com/api")
gazu.log_in("user@studio.com", "password")
```
Under the hood this POSTs to `/auth/login` with `{"email": "...", "password": "..."}` and receives a JWT access token + refresh token.
### Bot Authentication (pre-generated token)
Bots are non-physical users that don't count against subscription seats. Create them in Admin > Bots. Use the token directly:
```python
gazu.set_host("https://kitsu.mystudio.com/api")
gazu.set_token("bot_jwt_token_here")
```
### Token Lifecycle
- **Access token**: Short-lived JWT, passed as `Authorization: Bearer <token>` header
- **Refresh token**: Use `GET /auth/refresh-token` to get a new access token
- **Logout**: `GET /auth/logout`
- **Check auth**: `GET /auth/authenticated` (200 = valid, 401 = expired)
### 2FA Support
Kitsu supports TOTP, email OTP, FIDO/WebAuthn, and recovery codes. See `/auth/totp`, `/auth/email-otp`, `/auth/fido` endpoints.
### ADM Pipeline Authentication
In the ADM Gadget pipeline, credentials come from environment variables set by `adm_env.yml`:
- `TRACKER_URL` — Kitsu instance URL (must end with `/api`)
- `TRACKER_LOGIN` — email
- `TRACKER_PASSWORD` — password
- `TRACKER_PROJECT` — project name to connect to
The `Kitsu` adapter class (`gadget/src/gadget/resources/trackers/kitsu.py`) wraps gazu and handles connection/reconnection.
## Core Concepts
### Entity Hierarchy
```
Project
├── Episodes (optional, for TV shows)
│ └── Sequences
│ └── Shots
├── Sequences (for shorts/features)
│ └── Shots
├── Asset Types
│ └── Assets
├── Edits
├── Concepts
└── Scenes
```
### Data Model
Every entity in Kitsu is a dict with at minimum:
- `id` — UUID string
- `name` — display name
- `created_at` / `updated_at` — ISO timestamps
- `data` — custom metadata dict (called `custom_data` in Gadget after normalization)
- `project_id` — parent project UUID
### Key Relationships
- **Shot** → belongs to **Sequence** (via `parent_id`) → belongs to **Episode** (optional)
- **Asset** → belongs to **Asset Type** (via `entity_type_id`)
- **Task** → belongs to **Entity** (shot/asset) + **Task Type** + has **Task Status**
- **Comment** → belongs to **Task**, may have **Preview Files** and **Attachments**
- **Casting** → links Assets to Shots (with `nb_occurences`)
## gazu SDK Patterns
### Project Operations
```python
# List/find projects
projects = gazu.project.all_projects()
open_projects = gazu.project.all_open_projects()
project = gazu.project.get_project_by_name("My Project")
project = gazu.project.get_project(project_id)
# Create project
project = gazu.project.new_project("Name", production_type="short") # short|featurefilm|tvshow
# Team management
gazu.project.add_person_to_team(project, person)
gazu.project.remove_person_from_team(project, person)
team = gazu.project.get_team(project)
```
### Shot Operations
```python
# Episodes (TV shows only)
episode = gazu.shot.new_episode(project, "E01")
episodes = gazu.shot.all_episodes_for_project(project)
# Sequences
sequence = gazu.shot.new_sequence(project, "SQ010", episode=episode)
sequences = gazu.shot.all_sequences_for_project(project)
# Shots
shot = gazu.shot.new_shot(project, sequence, "SH0010",
nb_frames=100, frame_in=101, frame_out=200,
data={"custom_field": "value"})
shot = gazu.shot.get_shot(shot_id)
shot = gazu.shot.get_shot_by_name(sequence, "SH0010")
shots = gazu.shot.all_shots_for_sequence(sequence)
gazu.shot.update_shot(shot) # after modifying dict fields
gazu.shot.remove_shot(shot_id, force=True)
```
### Asset Operations
```python
# Asset types
asset_type = gazu.asset.new_asset_type("Character")
asset_types = gazu.asset.all_asset_types_for_project(project)
# Assets
asset = gazu.asset.new_asset(project, asset_type, "Hero",
description="Main character",
extra_data={"variant": "default"})
asset = gazu.asset.get_asset(asset_id)
asset = gazu.asset.get_asset_by_name(project, "Hero", asset_type)
assets = gazu.asset.all_assets_for_project(project)
gazu.asset.remove_asset(asset_id, force=True)
```
### Task Operations
```python
# Task types & statuses
task_type = gazu.task.get_task_type_by_name("Animation")
wip = gazu.task.get_task_status_by_short_name("wip")
done = gazu.task.get_task_status_by_short_name("done")
# Create tasks
task = gazu.task.new_task(entity, task_type, task_status=wip, assignees=[person])
# Find tasks
tasks = gazu.task.all_tasks_for_shot(shot)
tasks = gazu.task.all_tasks_for_asset(asset)
task = gazu.task.get_task_by_name(entity, task_type) # get_task_by_entity in some versions
# Assignment
gazu.task.assign_task(task, person)
# Time tracking
gazu.task.set_time_spent(task, person, "2024-03-18", duration=8*3600) # seconds
gazu.task.add_time_spent(task, person, "2024-03-18", duration=3600)
# Scheduling
task["start_date"] = "2024-03-01"
task["due_date"] = "2024-03-15"
task["estimation"] = 5 * 8 * 3600 # 5 days in seconds
gazu.task.update_task(task)
```
### Comments & Publishing
```python
# Add comment (also changes task status)
comment = gazu.task.add_comment(task, task_status,
comment="Looking good!",
person=person,
attachments=["/path/to/file.pdf"],
created_at=None)
# Add preview to comment
preview = gazu.task.add_preview(task, comment, "/path/to/render.mp4")
gazu.task.set_main_preview(preview) # set as entity thumbnail
# One-step publish shortcut
comment, preview = gazu.task.publish_preview(task, wip,
comment="WIP update",
preview_file_path="/path/to/file.mp4")
# Read comments
comments = gazu.task.all_comments_for_task(task)
last = gazu.task.get_last_comment_for_task(task)
# Download previews
gazu.files.download_preview_file(preview, "/path/to/output.mp4")
gazu.files.download_preview_file_thumbnail(preview, "/path/to/thumb.png")
```
### Casting (Breakdown)
```python
# Get casting
casting = gazu.casting.get_shot_casting(shot) # assets in a shot
cast_in = gazu.casting.get_asset_cast_in(asset) # shots using an asset
# Update casting
gazu.casting.update_shot_casting(project, shot_id, [
{"asset_id": asset1_id, "nb_occurences": 2},
{"asset_id": asset2_id, "nb_occurences": 1},
])
```
### Persons & Teams
```python
person = gazu.person.new_person("John", "Doe", "john@studio.com",
role="user", departments=[dept])
persons = gazu.person.all_persons()
person = gazu.person.get_person_by_full_name("John Doe")
gazu.person.add_person_to_department(person, department)
```
### Playlists
```python
playlist = gazu.playlist.new_playlist(project, "Daily Review",
for_client=False, for_entity="shot")
gazu.playlist.add_entity_to_playlist(playlist, entity, preview_file=preview)
```
### Event Listeners (Real-time)
```python
gazu.set_event_host("https://kitsu.mystudio.com") # note: no /api suffix
event_client = gazu.events.init()
def on_task_status_changed(data):
print(f"Task {data['task_id']} status changed")
gazu.events.add_listener(event_client, "task:status-changed", on_task_status_changed)
gazu.events.run_client(event_client) # blocks current thread
```
Event naming: `entity:action` (e.g., `asset:new`, `shot:update`, `comment:new`, `task:assign`).
Most entities emit `new`, `update`, `delete`. See `references/events.md` for the full list.
### Caching
```python
gazu.cache.enable() # enable in-memory cache for all read ops
gazu.cache.disable()
gazu.cache.clear_all()
# Per-function control
gazu.asset.all_assets.set_expire(120) # seconds
gazu.asset.all_assets.clear_cache()
gazu.asset.all_assets.disable_cache()
```
### Low-level Client
When gazu doesn't wrap an endpoint, use the raw client:
```python
# GET
data = gazu.client.get("data/projects")
data = gazu.client.fetch_all("tasks", {"project_id": pid, "task_type_id": ttid})
data = gazu.client.fetch_one("projects", project_id)
data = gazu.client.fetch_first("projects", {"name": "MyProject"})
# POST
result = gazu.client.post("data/projects", {"name": "New Project"})
# PUT
result = gazu.client.put(f"data/entities/{entity_id}", updated_data)
# Pagination
page1 = gazu.client.fetch_all("tasks?page=1") # 100 per page
```
### Search
```python
# Full-text search
results = gazu.search.search_entities("bird")
# Returns: {"persons": [...], "assets": [...], "shots": [...]}
# REST API search
results = gazu.client.post("data/search", {
"query": "hero",
"project_id": project_id,
"limit": 10,
"offset": 0,
"index_names": ["assets"] # filter to specific entity types
})
```
## Roles & Permissions
| Role | Access Level |
|------|-------------|
| **Admin** (Studio Manager) | Full read/write to all productions and settings |
| **Manager** (Production Manager) | Create assets/shots, manage tasks, post comments — no studio settings |
| **Supervisor** (Department Lead) | Read/write within assigned departments |
| **User** (Artist) | Comment/upload on assigned tasks only |
| **Vendor** | Like User but can only see assigned tasks |
| **Client** | View-only on assigned productions, client playlists only |
## Custom Actions
Custom Actions trigger HTTP POST requests from the Kitsu web UI to your endpoint. Created by admins in Admin > Custom Actions.
Payload sent to your endpoint:
```json
{
"personid": "uuid",
"personemail": "user@studio.com",
"projectid": "uuid",
"currentpath": "/productions/{id}/assets",
"currentserver": "kitsu.mystudio.com",
"selection": ["task_uuid_1", "task_uuid_2"],
"entitytype": "asset"
}
```
## ADM Gadget Integration
The Gadget pipeline's `Kitsu` adapter (`gadget/src/gadget/resources/trackers/kitsu.py`) wraps gazu with these conventions:
- **ID normalization**: `get_id()` accepts strings (UUID), dicts (extracts `["id"]`), or Gadget entity objects (uses `.id`)
- **Data normalization**: `_norm_data()` renames `data``custom_data` to avoid collision with Python dict usage
- **Task normalization**: `retake_count``nb_retakes`, `for_entity``for_shots` boolean
- **Comment normalization**: `attachment_files``attachments`, adds index-based `id` to checklist items, renames preview `original_name``name`
- **Shot creation**: Uses raw `gazu.client.post()` because gazu's `new_shot` didn't support all fields needed
Key Gadget patterns:
```python
# Gadget entity-level usage
project = Project.from_env() # loads from env vars
shot = project.shots.get(name="sq170_sh0224")
task = shot.tasks.fetch("Anim3D")
task.comments.new(comment="...", preview=["/path/to/img.png"], set_main_preview=True)
```
## Detailed References
For the complete endpoint catalog (all 493 endpoints), see `references/endpoints.md`.
For the full event types list, see `references/events.md`.
When you need details about a specific endpoint's parameters or response format, fetch the OpenAPI spec:
```bash
curl -s https://api-docs.kitsu.cloud/source.json | python3 -m json.tool
```
Or read it programmatically:
```python
import json, urllib.request
spec = json.loads(urllib.request.urlopen("https://api-docs.kitsu.cloud/source.json").read())
endpoint = spec["paths"]["/data/shots/{shot_id}"]
```

View File

@ -0,0 +1,742 @@
# Kitsu API — Complete Endpoint Catalog
**493 endpoints** across 24 categories. Base URL: `https://<your-kitsu>/api`
All endpoints require JWT authentication via `Authorization: Bearer <token>` header, except `/auth/login` and `/auth/register`.
## Table of Contents
1. [Authentication](#authentication) — Login, logout, 2FA, SAML
2. [Projects](#projects) — CRUD, settings, team, stats
3. [Shots](#shots) — Shots, sequences, episodes, scenes
4. [Assets](#assets) — Assets, asset types, instances, sharing
5. [Tasks](#tasks) — Tasks, task types, task statuses, assignments, time tracking
6. [Comments](#comments) — Comments, replies, attachments
7. [Previews](#previews) — Preview files, thumbnails, movies
8. [Files](#files) — Working files, output files, software
9. [Casting/Breakdown](#casting) — Entity casting, asset instances
10. [Persons](#persons) — Users, departments, day-offs, time spents
11. [Playlists](#playlists) — Playlists, build jobs
12. [Events](#events) — Event log, login logs
13. [News](#news) — Activity feed
14. [Notifications](#notifications) — User notifications
15. [Search](#search) — Full-text search, filters
16. [Chat](#chat) — Entity chat, messages
17. [Entities](#entities) — Generic entity operations
18. [Concepts & Edits](#concepts-edits) — Concept art, edit entities
19. [Export/Import](#export-import) — CSV, Kitsu, ShotGrid, OTIO
20. [User Context](#user-context) — Current user's data
21. [Custom Actions](#custom-actions) — Webhook-like triggers
22. [Admin](#admin) — Status, config, organisations, studios
23. [Budgets & Scheduling](#budgets-scheduling) — Budgets, milestones, schedule items
24. [Media Files](#media-files) — Pictures, movies, thumbnails
---
## Authentication
| Method | Path | Description |
|--------|------|-------------|
| POST | `/auth/login` | Login with email/password, returns JWT |
| GET | `/auth/logout` | Invalidate current token |
| GET | `/auth/authenticated` | Check if token is valid (200/401) |
| GET | `/auth/refresh-token` | Get new access token |
| POST | `/auth/register` | Register new user |
| POST | `/auth/change-password` | Change password (old_password, password, password_2) |
| POST | `/auth/reset-password` | Request password reset email |
| PUT | `/auth/reset-password` | Complete password reset (token, password) |
| PUT/POST/DELETE | `/auth/totp` | Pre-enable/enable/disable TOTP 2FA |
| GET/POST/DELETE | `/auth/email-otp` | Email OTP 2FA management |
| GET/PUT/POST/DELETE | `/auth/fido` | FIDO/WebAuthn device management |
| PUT | `/auth/recovery-codes` | Generate recovery codes |
| GET | `/auth/saml/login` | SAML SSO login redirect |
| POST | `/auth/saml/sso` | SAML SSO callback |
## Projects
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/projects` | List all / create project |
| GET | `/data/projects/all` | All projects (admin) |
| GET | `/data/projects/open` | Open projects only |
| GET | `/data/projects/news` | News across all projects |
| GET/PUT/DELETE | `/data/projects/{id}` | Get/update/delete project |
| GET/POST | `/data/projects/{id}/team` | Get/add team members |
| DELETE | `/data/projects/{id}/team/{person_id}` | Remove from team |
| GET | `/data/projects/{id}/task-types` | Project task types |
| GET | `/data/projects/{id}/asset-types` | Project asset types |
| GET | `/data/projects/{id}/assets` | Project assets |
| GET | `/data/projects/{id}/comments` | All project comments |
| GET | `/data/projects/{id}/preview-files` | All project previews |
| GET | `/data/projects/{id}/attachment-files` | All project attachments |
| GET | `/data/projects/{id}/output-files` | All project output files |
| GET | `/data/projects/{id}/news` | Project news feed |
| GET | `/data/projects/{id}/news/{news_id}` | Specific news item |
| GET | `/data/projects/{id}/notifications` | Project notifications |
| GET | `/data/projects/{id}/playlists` | Project playlists |
| GET | `/data/projects/{id}/playlists/all` | All playlists including temp |
| POST | `/data/projects/{id}/playlists/temp` | Create temp playlist |
| GET | `/data/projects/{id}/subscriptions` | Project subscriptions |
| GET | `/data/projects/{id}/tasks` | All project tasks |
| GET | `/data/projects/{id}/time-spents` | Project time tracking |
| GET | `/data/projects/{id}/entity-links` | Project entity links |
| DELETE | `/data/projects/{id}/entity-links/{link_id}` | Remove entity link |
| GET | `/data/projects/{id}/build-jobs` | Build jobs for project |
| GET | `/data/projects/{id}/day-offs` | Project day offs |
### Project Settings
| Method | Path | Description |
|--------|------|-------------|
| POST | `/data/projects/{id}/settings/asset-types` | Add asset type to project |
| DELETE | `/data/projects/{id}/settings/asset-types/{at_id}` | Remove asset type |
| POST | `/data/projects/{id}/settings/task-types` | Add task type to project |
| DELETE | `/data/projects/{id}/settings/task-types/{tt_id}` | Remove task type |
| GET/POST | `/data/projects/{id}/settings/task-status` | Get/add task statuses |
| DELETE | `/data/projects/{id}/settings/task-status/{ts_id}` | Remove task status |
| GET/POST | `/data/projects/{id}/settings/status-automations` | Status automations |
| DELETE | `/data/projects/{id}/settings/status-automations/{sa_id}` | Remove automation |
| GET/POST | `/data/projects/{id}/settings/preview-background-files` | Preview BG files |
| DELETE | `/data/projects/{id}/settings/preview-background-files/{pbf_id}` | Remove BG |
| POST | `/actions/projects/{id}/set-file-tree` | Set project file tree template |
| POST | `/actions/projects/{id}/delete-tasks` | Batch delete tasks |
### Project Metadata
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/projects/{id}/metadata-descriptors` | Custom metadata fields |
| POST | `/data/projects/{id}/metadata-descriptors/reorder` | Reorder descriptors |
| GET/PUT/DELETE | `/data/projects/{id}/metadata-descriptors/{desc_id}` | CRUD descriptor |
### Project Stats & Quotas
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/projects/{id}/episodes/stats` | Episode statistics |
| GET | `/data/projects/{id}/episodes/retake-stats` | Retake statistics |
| GET | `/data/projects/{id}/quotas/{task_type_id}` | Quotas by task type |
| GET | `/data/projects/{id}/quotas/persons/{person_id}` | Personal quotas |
| GET | `/data/projects/{id}/task-types/{tt_id}/time-spents` | Time by task type |
## Shots
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/shots` | All shots (filterable) |
| GET | `/data/shots/all` | All shots (admin) |
| GET | `/data/shots/with-tasks` | Shots with embedded tasks |
| GET/PUT/DELETE | `/data/shots/{id}` | Get/update/delete shot |
| GET | `/data/shots/{id}/tasks` | Shot's tasks |
| GET | `/data/shots/{id}/task-types` | Shot's task types |
| GET | `/data/shots/{id}/assets` | Assets linked to shot |
| GET | `/data/shots/{id}/asset-types` | Asset types in shot |
| GET | `/data/shots/{id}/preview-files` | Shot preview files |
| GET | `/data/shots/{id}/versions` | Shot versions |
| GET/POST | `/data/shots/{id}/asset-instances` | Shot asset instances |
| DELETE | `/data/shots/{id}/asset-instances/{ai_id}` | Remove instance |
| POST | `/data/projects/{id}/shots` | Create shot in project |
### Sequences
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/sequences` | All sequences |
| GET | `/data/sequences/with-tasks` | Sequences with tasks |
| GET/DELETE | `/data/sequences/{id}` | Get/delete sequence |
| GET | `/data/sequences/{id}/shots` | Shots in sequence |
| GET | `/data/sequences/{id}/shot-tasks` | All shot tasks in sequence |
| GET | `/data/sequences/{id}/scenes` | Scenes in sequence |
| GET | `/data/sequences/{id}/task-types` | Sequence task types |
| GET | `/data/sequences/{id}/tasks` | Sequence tasks |
| GET/POST | `/data/projects/{id}/sequences` | Project sequences |
### Episodes
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/episodes` | All episodes |
| GET | `/data/episodes/with-tasks` | Episodes with tasks |
| GET/DELETE | `/data/episodes/{id}` | Get/delete episode |
| GET | `/data/episodes/{id}/sequences` | Episode sequences |
| GET | `/data/episodes/{id}/shots` | Episode shots |
| GET | `/data/episodes/{id}/shot-tasks` | Shot tasks for episode |
| GET | `/data/episodes/{id}/asset-tasks` | Asset tasks for episode |
| GET | `/data/episodes/{id}/edit-tasks` | Edit tasks for episode |
| GET | `/data/episodes/{id}/edits` | Edits for episode |
| GET | `/data/episodes/{id}/task-types` | Episode task types |
| GET | `/data/episodes/{id}/tasks` | Episode tasks |
| GET/POST | `/data/projects/{id}/episodes` | Project episodes |
| GET | `/data/projects/{id}/episodes/casting` | All episode casting |
| GET | `/data/projects/{id}/episodes/{ep_id}/playlists` | Episode playlists |
| GET | `/data/projects/{id}/episodes/{ep_id}/sequences/all/casting` | Casting for all sequences |
| GET | `/data/projects/{id}/episodes/{ep_id}/assets/shared-used` | Shared assets in episode |
### Scenes
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/scenes/all` | All scenes |
| GET | `/data/scenes/with-tasks` | Scenes with tasks |
| GET/DELETE | `/data/scenes/{id}` | Get/delete scene |
| GET/POST | `/data/scenes/{id}/asset-instances` | Scene asset instances |
| GET | `/data/scenes/{id}/camera-instances` | Camera instances |
| GET/POST | `/data/scenes/{id}/shots` | Scene shots |
| DELETE | `/data/scenes/{id}/shots/{shot_id}` | Remove shot from scene |
| GET | `/data/scenes/{id}/task-types` | Scene task types |
| GET | `/data/scenes/{id}/tasks` | Scene tasks |
| GET/POST | `/data/projects/{id}/scenes` | Project scenes |
## Assets
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/assets` | All assets (filterable by project_id, asset_type_id) |
| GET | `/data/assets/all` | All assets (admin) |
| GET | `/data/assets/with-tasks` | Assets with embedded tasks |
| GET/DELETE | `/data/assets/{id}` | Get/delete asset (force=true to force) |
| GET | `/data/assets/{id}/tasks` | Asset's tasks |
| GET | `/data/assets/{id}/task-types` | Asset's task types |
| GET | `/data/assets/{id}/assets` | Linked assets |
| GET | `/data/assets/{id}/cast-in` | Shots this asset appears in |
| GET/PUT | `/data/assets/{id}/casting` | Get/set asset casting |
| GET | `/data/assets/{id}/shot-asset-instances` | Instances in shots |
| GET | `/data/assets/{id}/scene-asset-instances` | Instances in scenes |
| GET/POST | `/data/assets/{id}/asset-asset-instances` | Asset instances |
| GET | `/data/asset-types` | All asset types |
| GET | `/data/asset-types/{id}` | Specific asset type |
| GET | `/data/projects/{id}/asset-types` | Project asset types |
| GET | `/data/projects/{id}/asset-types/{at_id}/assets` | Assets of type |
| POST | `/data/projects/{id}/asset-types/{at_id}/assets/new` | Create asset |
| GET | `/data/projects/{id}/asset-types/{at_id}/casting` | Casting by type |
| GET | `/data/projects/{id}/assets` | Project assets |
| GET | `/data/projects/{id}/assets/shared-used` | Shared assets |
### Asset Sharing
| Method | Path | Description |
|--------|------|-------------|
| POST | `/actions/assets/share` | Share assets across projects |
| POST | `/actions/projects/{id}/assets/share` | Share project assets |
| POST | `/actions/projects/{id}/asset-types/{at_id}/assets/share` | Share by type |
## Tasks
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/tasks` | List/create tasks |
| GET | `/data/tasks/open-tasks` | Open tasks |
| GET | `/data/tasks/open-tasks/stats` | Open tasks stats |
| GET/PUT/DELETE | `/data/tasks/{id}` | Get/update/delete task |
| GET | `/data/tasks/{id}/full` | Full task with all relations |
| GET | `/data/tasks/{id}/comments` | Task comments |
| GET/DELETE | `/data/tasks/{id}/comments/{cid}` | Get/delete comment |
| POST | `/data/tasks/{id}/comments/{cid}/reply` | Reply to comment |
| DELETE | `/data/tasks/{id}/comments/{cid}/reply/{rid}` | Delete reply |
| POST | `/data/tasks/{id}/comments/{cid}/ack` | Acknowledge comment |
| DELETE | `/data/tasks/{id}/comments/{cid}/attachments/{aid}` | Delete attachment |
| GET | `/data/tasks/{id}/previews` | Task preview files |
| GET | `/data/tasks/{id}/attachment-files` | Task attachments |
| GET | `/data/tasks/{id}/working-files` | Task working files |
| GET | `/data/tasks/{id}/working-files/last-revisions` | Latest working files |
| POST | `/data/tasks/{id}/working-files/new` | Create working file |
| POST | `/data/tasks/{id}/working-file-path` | Get working file path |
### Task Actions
| Method | Path | Description |
|--------|------|-------------|
| POST | `/actions/tasks/{id}/comment` | Add comment to task |
| POST | `/actions/tasks/{id}/batch-comment` | Batch comment |
| POST | `/actions/tasks/batch-comment` | Batch comment (multi-task) |
| PUT | `/actions/tasks/{id}/assign` | Assign task |
| PUT | `/actions/tasks/clear-assignation` | Clear assignments |
| PUT | `/actions/tasks/{id}/set-main-preview` | Set main preview |
| PUT | `/actions/tasks/{id}/to-review` | Send to review |
| POST | `/actions/tasks/{id}/comments/{cid}/add-preview` | Add preview to comment |
| POST | `/actions/tasks/{id}/comments/{cid}/add-attachment` | Add attachment |
| POST/DELETE | `/actions/tasks/{id}/comments/{cid}/preview-files/{pfid}` | Manage previews |
| POST | `/actions/projects/{id}/tasks/comment-many` | Comment many tasks |
### Task Creation (Bulk)
| Method | Path | Description |
|--------|------|-------------|
| POST | `/actions/projects/{id}/task-types/{tt_id}/shots/create-tasks` | Create tasks for all shots |
| POST | `/actions/projects/{id}/task-types/{tt_id}/assets/create-tasks` | Create tasks for all assets |
| POST | `/actions/projects/{id}/task-types/{tt_id}/edits/create-tasks` | Create tasks for all edits |
| POST | `/actions/projects/{id}/task-types/{tt_id}/concepts/create-tasks` | Create tasks for concepts |
| DELETE | `/actions/projects/{id}/task-types/{tt_id}/delete-tasks` | Delete all tasks of type |
### Time Tracking
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/time-spents/` | List/create time spents |
| GET/PUT/DELETE | `/data/time-spents/{id}` | CRUD time spent |
| GET | `/actions/tasks/{id}/time-spents` | Task time spents |
| GET | `/actions/tasks/{id}/time-spents/{date}` | Task time on date |
| POST/DELETE | `/actions/tasks/{id}/time-spents/{date}/persons/{pid}` | Set/delete person time |
| POST | `/actions/tasks/{id}/time-spents/{date}/persons/{pid}/add` | Add time |
### Task Types & Statuses
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/task-types` | List/create task types |
| GET/PUT/DELETE | `/data/task-types/{id}` | CRUD task type |
| GET/POST | `/data/task-status` | List/create task statuses |
| GET/PUT/DELETE | `/data/task-status/{id}` | CRUD task status |
| POST | `/data/task-type-links` | Link task types |
| POST | `/data/task-status-links` | Link task statuses |
| POST | `/actions/projects/{id}/task-types/{tt_id}/set-shot-nb-frames` | Set frame counts |
## Comments
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/comments` | List/create comments |
| GET/PUT/DELETE | `/data/comments/{id}` | CRUD comment |
## Previews
### Preview Actions
| Method | Path | Description |
|--------|------|-------------|
| PUT | `/actions/preview-files/{id}/set-main-preview` | Set as main preview |
| PUT | `/actions/preview-files/{id}/update-annotations` | Update annotations |
| PUT | `/actions/preview-files/{id}/update-position` | Update position |
| GET | `/actions/preview-files/{id}/extract-frame` | Extract frame |
| GET | `/actions/preview-files/{id}/extract-tile` | Extract tile |
### Preview Data
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/preview-files` | List/create preview files |
| GET/PUT/DELETE | `/data/preview-files/{id}` | CRUD preview file |
| GET/POST | `/data/preview-background-files` | Background files |
| GET/PUT/DELETE | `/data/preview-background-files/{id}` | CRUD background file |
## Files
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/files/{id}` | Get file info |
| GET/POST | `/data/working-files` | List/create working files |
| GET/PUT/DELETE | `/data/working-files/{id}` | CRUD working file |
| GET/POST | `/data/working-files/{id}/file` | Upload/download file |
| PUT | `/actions/working-files/{id}/comment` | Comment on working file |
| PUT | `/actions/working-files/{id}/modified` | Mark as modified |
| GET/POST | `/data/output-files` | List/create output files |
| GET/PUT/DELETE | `/data/output-files/{id}` | CRUD output file |
| GET/POST | `/data/output-types` | List/create output types |
| GET/PUT/DELETE | `/data/output-types/{id}` | CRUD output type |
| GET/POST | `/data/attachment-files` | List/create attachments |
| GET/PUT/DELETE | `/data/attachment-files/{id}` | CRUD attachment |
| GET | `/data/attachment-files/{id}/file/{filename}` | Download attachment |
| GET/POST | `/data/softwares` | List/create software entries |
| GET/PUT/DELETE | `/data/softwares/{id}` | CRUD software |
| GET/POST | `/data/file-status/` | File statuses |
| GET/PUT/DELETE | `/data/file-status/{id}` | CRUD file status |
### Entity File Operations
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/entities/{id}/working-files` | Entity working files |
| GET | `/data/entities/{id}/output-files` | Entity output files |
| GET | `/data/entities/{id}/output-files/last-revisions` | Latest output revisions |
| POST | `/data/entities/{id}/output-files/new` | Create output file |
| POST | `/data/entities/{id}/output-files/next-revision` | Next revision number |
| POST | `/data/entities/{id}/output-file-path` | Get output file path |
| GET | `/data/entities/{id}/output-types` | Entity output types |
| GET | `/data/entities/{id}/output-types/{ot_id}/output-files` | Files by output type |
| GET | `/data/entities/{id}/preview-files` | Entity preview files |
### Asset Instance File Operations
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/asset-instances/{ai_id}/output-files` | Instance output files |
| GET | `/data/asset-instances/{ai_id}/entities/{te_id}/output-files/last-revisions` | Latest revisions |
| POST | `/data/asset-instances/{ai_id}/entities/{te_id}/output-files/new` | Create output |
| POST | `/data/asset-instances/{ai_id}/entities/{te_id}/output-files/next-revision` | Next revision |
| POST | `/data/asset-instances/{ai_id}/entities/{te_id}/output-file-path` | Get path |
| GET | `/data/asset-instances/{ai_id}/entities/{te_id}/output-types` | Output types |
| GET | `/data/asset-instances/{ai_id}/entities/{te_id}/output-types/{ot_id}/output-files` | Files |
## Casting
| Method | Path | Description |
|--------|------|-------------|
| GET/PUT | `/data/projects/{id}/entities/{eid}/casting` | Entity casting |
| GET | `/data/projects/{id}/asset-types/{at_id}/casting` | Casting by asset type |
| GET | `/data/projects/{id}/sequences/all/casting` | All sequence casting |
| GET | `/data/projects/{id}/sequences/{sid}/casting` | Sequence casting |
| GET/POST | `/data/asset-instances/` | Asset instances |
| GET/PUT/DELETE | `/data/asset-instances/{id}` | CRUD asset instance |
## Persons
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/persons` | List/create persons |
| GET/PUT/DELETE | `/data/persons/{id}` | CRUD person |
| GET | `/data/persons/{id}/tasks` | Person's tasks |
| GET | `/data/persons/{id}/done-tasks` | Person's completed tasks |
| GET | `/data/persons/{id}/time-spents` | All time spents |
| GET | `/data/persons/{id}/time-spents/{date}` | Time on specific date |
| GET | `/data/persons/{id}/time-spents/day/{y}/{m}/{d}` | Daily time |
| GET | `/data/persons/{id}/time-spents/week/{y}/{w}` | Weekly time |
| GET | `/data/persons/{id}/time-spents/month/{y}/{m}` | Monthly time |
| GET | `/data/persons/{id}/time-spents/month/all/{y}/{m}` | Monthly all |
| GET | `/data/persons/{id}/time-spents/year/{y}` | Yearly time |
| GET | `/data/persons/{id}/related-tasks/{tt_id}` | Related tasks |
| GET | `/data/persons/{id}/quota-shots/day/{y}/{m}/{d}` | Daily quota |
| GET | `/data/persons/{id}/quota-shots/week/{y}/{w}` | Weekly quota |
| GET | `/data/persons/{id}/quota-shots/month/{y}/{m}` | Monthly quota |
| GET/POST | `/data/persons/{id}/desktop-login-logs` | Login logs |
### Person Aggregate Tables
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/persons/time-spents/day-table/{y}/{m}` | All persons daily |
| GET | `/data/persons/time-spents/week-table/{y}` | All persons weekly |
| GET | `/data/persons/time-spents/month-table/{y}` | All persons monthly |
| GET | `/data/persons/time-spents/year-table/` | All persons yearly |
| GET | `/data/persons/task-dates` | All persons task dates |
| GET | `/data/persons/presence-logs/{month_date}` | Presence logs |
### Day Offs
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/day-offs/` | List/create day offs |
| GET/PUT/DELETE | `/data/day-offs/{id}` | CRUD day off |
| GET | `/data/persons/{id}/day-offs` | Person day offs |
| GET | `/data/persons/{id}/day-offs/{date}` | Day offs on date |
| GET | `/data/persons/{id}/day-offs/week/{y}/{w}` | Weekly day offs |
| GET | `/data/persons/{id}/day-offs/month/{y}/{m}` | Monthly day offs |
| GET | `/data/persons/{id}/day-offs/year/{y}` | Yearly day offs |
| GET | `/data/persons/day-offs/{y}/{m}` | All persons day offs |
### Person Actions
| Method | Path | Description |
|--------|------|-------------|
| PUT | `/actions/persons/{id}/assign` | Assign person |
| POST | `/actions/persons/{id}/change-password` | Change password |
| DELETE | `/actions/persons/{id}/clear-avatar` | Clear avatar |
| POST | `/actions/persons/{id}/departments/add` | Add to department |
| DELETE | `/actions/persons/{id}/departments/{did}` | Remove from dept |
| DELETE | `/actions/persons/{id}/disable-two-factor-authentication` | Disable 2FA |
| GET | `/actions/persons/{id}/invite` | Send invite |
### Departments
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/departments` | List/create departments |
| GET/PUT/DELETE | `/data/departments/{id}` | CRUD department |
| GET | `/data/departments/hardware-items` | All hardware items |
| GET | `/data/departments/software-licenses` | All software licenses |
| POST | `/data/departments/{id}/hardware-items` | Add hardware |
| GET/DELETE | `/data/departments/{id}/hardware-items/{hid}` | Get/remove |
| POST | `/data/departments/{id}/software-licenses` | Add license |
| GET/DELETE | `/data/departments/{id}/software-licenses/{sid}` | Get/remove |
## Playlists
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/playlists/` | List/create playlists |
| GET/PUT/DELETE | `/data/playlists/{id}` | CRUD playlist |
| GET | `/data/playlists/entities/{eid}/preview-files` | Entity previews in playlists |
| GET | `/data/playlists/preview-files/running` | Running preview builds |
| GET | `/data/playlists/{id}/build/mp4` | Build MP4 |
| GET | `/data/playlists/{id}/download/zip` | Download ZIP |
| GET/DELETE | `/data/playlists/{id}/jobs/{jid}` | Build job status |
| GET | `/data/playlists/{id}/jobs/{jid}/build/mp4` | Job MP4 |
| POST | `/data/playlists/{id}/notify-clients` | Notify clients |
| POST | `/actions/playlists/{id}/add-entity` | Add entity to playlist |
## Events
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/events/` | List/create events |
| GET | `/data/events/last` | Recent events (page_size, before, after, only_files) |
| GET | `/data/events/login-logs/last` | Recent login logs |
| GET/PUT/DELETE | `/data/events/{id}` | CRUD event |
## News
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/news/` | List/create news |
| GET/PUT/DELETE | `/data/news/{id}` | CRUD news |
| GET | `/data/entities/{id}/news` | Entity news |
## Notifications
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/notifications/` | List/create notifications |
| GET/PUT/DELETE | `/data/notifications/{id}` | CRUD notification |
## Search
| Method | Path | Description |
|--------|------|-------------|
| POST | `/data/search` | Full-text search (query, project_id, limit, offset, index_names) |
| GET/POST | `/data/search-filters/` | Saved search filters |
| GET/PUT/DELETE | `/data/search-filters/{id}` | CRUD search filter |
| GET/POST | `/data/search-filter-groups/` | Filter groups |
| GET/PUT/DELETE | `/data/search-filter-groups/{id}` | CRUD filter group |
## Chat
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/chats/` | List/create chats |
| GET/PUT/DELETE | `/data/chats/{id}` | CRUD chat |
| GET/POST | `/data/chat-messages/` | List/create messages |
| GET/PUT/DELETE | `/data/chat-messages/{id}` | CRUD message |
| GET | `/data/entities/{eid}/chat` | Entity chat |
| GET/POST | `/data/entities/{eid}/chat/messages` | Entity chat messages |
| GET/DELETE | `/data/entities/{eid}/chat/messages/{mid}` | Get/delete message |
| POST/DELETE | `/actions/user/chats/{eid}/join` | Join/leave entity chat |
## Entities (Generic)
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/entities` | List/create entities |
| GET/PUT/DELETE | `/data/entities/{id}` | CRUD entity |
| POST | `/data/entities/guess_from_path` | Guess entity from file path |
| GET | `/data/entities/{id}/entities-linked/with-tasks` | Linked entities with tasks |
| GET | `/data/entities/{id}/time-spents` | Entity time spents |
| GET | `/data/entities/{id}/task-types/{tt_id}/tasks` | Tasks by type |
| GET/POST | `/data/entity-links/` | Entity links |
| GET/PUT/DELETE | `/data/entity-links/{id}` | CRUD entity link |
| GET/POST | `/data/entity-types` | Entity types |
| GET/PUT/DELETE | `/data/entity-types/{id}` | CRUD entity type |
## Concepts & Edits
### Concepts
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/concepts` | All concepts |
| GET | `/data/concepts/with-tasks` | Concepts with tasks |
| GET/DELETE | `/data/concepts/{id}` | Get/delete concept |
| GET | `/data/concepts/{id}/preview-files` | Concept previews |
| GET | `/data/concepts/{id}/task-types` | Concept task types |
| GET | `/data/concepts/{id}/tasks` | Concept tasks |
| GET/POST | `/data/projects/{id}/concepts` | Project concepts |
### Edits
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/edits` | All edits |
| GET | `/data/edits/all` | All edits (admin) |
| GET | `/data/edits/with-tasks` | Edits with tasks |
| GET/DELETE | `/data/edits/{id}` | Get/delete edit |
| GET | `/data/edits/{id}/preview-files` | Edit previews |
| GET | `/data/edits/{id}/task-types` | Edit task types |
| GET | `/data/edits/{id}/tasks` | Edit tasks |
| GET | `/data/edits/{id}/versions` | Edit versions |
| GET/POST | `/data/projects/{id}/edits` | Project edits |
## Export/Import
### CSV Export
| Method | Path | Description |
|--------|------|-------------|
| GET | `/export/csv/persons.csv` | Export persons |
| GET | `/export/csv/projects.csv` | Export projects |
| GET | `/export/csv/task-types.csv` | Export task types |
| GET | `/export/csv/tasks.csv` | Export tasks |
| GET | `/export/csv/time-spents.csv` | Export time spents |
| GET | `/export/csv/projects/{id}/assets.csv` | Export assets |
| GET | `/export/csv/projects/{id}/shots.csv` | Export shots |
| GET | `/export/csv/projects/{id}/edits.csv` | Export edits |
| GET | `/export/csv/projects/{id}/casting.csv` | Export casting |
| GET | `/export/csv/playlists/{id}` | Export playlist |
### CSV Import
| Method | Path | Description |
|--------|------|-------------|
| POST | `/import/csv/persons` | Import persons |
| POST | `/import/csv/projects/{id}/assets` | Import assets |
| POST | `/import/csv/projects/{id}/shots` | Import shots |
| POST | `/import/csv/projects/{id}/edits` | Import edits |
| POST | `/import/csv/projects/{id}/casting` | Import casting |
| POST | `/import/csv/projects/{id}/task-types/{tt_id}/estimations` | Import estimations |
| POST | `/import/csv/projects/{id}/episodes/{ep_id}/task-types/{tt_id}/estimations` | Episode estimations |
### Kitsu Import
| Method | Path | Description |
|--------|------|-------------|
| POST | `/import/kitsu/projects` | Import from Kitsu |
| POST | `/import/kitsu/entities` | Import entities |
| POST | `/import/kitsu/tasks` | Import tasks |
| POST | `/import/kitsu/comments` | Import comments |
| POST | `/import/kitsu/entity-links` | Import links |
### OTIO Import
| Method | Path | Description |
|--------|------|-------------|
| POST | `/import/otio/projects/{id}` | Import OTIO |
| POST | `/import/otio/projects/{id}/episodes/{ep_id}` | Import OTIO with episode |
## User Context (Current User)
| Method | Path | Description |
|--------|------|-------------|
| GET | `/data/user/context` | Current user context |
| GET | `/data/user/tasks` | My tasks |
| GET | `/data/user/tasks-to-check` | Tasks to review |
| GET | `/data/user/done-tasks` | My completed tasks |
| GET | `/data/user/notifications` | My notifications |
| GET/PUT | `/data/user/notifications/{id}` | Get/mark notification |
| POST | `/actions/user/notifications/mark-all-as-read` | Mark all read |
| GET | `/data/user/chats` | My chats |
| GET | `/data/user/time-spents` | My time spents |
| GET | `/data/user/time-spents/{date}` | My time on date |
| GET | `/data/user/day-offs/{date}` | My day offs |
| GET/POST | `/data/user/filters` | My saved filters |
| PUT/DELETE | `/data/user/filters/{id}` | Update/delete filter |
| GET/POST | `/data/user/filter-groups` | My filter groups |
| GET/PUT/DELETE | `/data/user/filter-groups/{id}` | CRUD filter group |
| GET/POST | `/data/user/desktop-login-logs` | Desktop login logs |
| DELETE | `/actions/user/clear-avatar` | Clear my avatar |
| GET | `/data/user/projects/open` | My open projects |
| GET | `/data/user/projects/{id}/asset-types` | My project asset types |
| GET | `/data/user/projects/{id}/asset-types/{at_id}/assets` | My project assets |
| GET | `/data/user/projects/{id}/episodes` | My project episodes |
| GET | `/data/user/projects/{id}/sequences` | My project sequences |
| GET | `/data/user/projects/{id}/task-types/{tt_id}/sequence-subscriptions` | My subscriptions |
| GET | `/data/user/assets/{id}/task-types` | My asset task types |
| GET | `/data/user/assets/{id}/tasks` | My asset tasks |
| GET | `/data/user/shots/{id}/task-types` | My shot task types |
| GET | `/data/user/shots/{id}/tasks` | My shot tasks |
| GET | `/data/user/sequences/{id}/shots` | My sequence shots |
| GET | `/data/user/sequences/{id}/scenes` | My sequence scenes |
| GET | `/data/user/sequences/{id}/task-types` | My sequence task types |
| GET | `/data/user/sequences/{id}/tasks` | My sequence tasks |
| GET | `/data/user/scenes/{id}/task-types` | My scene task types |
| GET | `/data/user/scenes/{id}/tasks` | My scene tasks |
| GET | `/data/user/entities/{sid}/task-types/{tt_id}/subscribed` | Subscription status |
| GET | `/data/user/tasks/{id}/subscribed` | Task subscription status |
| GET | `/data/user/tasks/{id}/time-spents/{date}` | My task time |
| POST | `/actions/user/tasks/{id}/subscribe` | Subscribe to task |
| DELETE | `/actions/user/tasks/{id}/unsubscribe` | Unsubscribe from task |
| POST | `/actions/user/sequences/{sid}/task-types/{tt_id}/subscribe` | Subscribe to sequence |
| DELETE | `/actions/user/sequences/{sid}/task-types/{tt_id}/unsubscribe` | Unsubscribe |
## Custom Actions
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/custom-actions/` | List/create custom actions |
| GET/PUT/DELETE | `/data/custom-actions/{id}` | CRUD custom action |
## Admin & System
| Method | Path | Description |
|--------|------|-------------|
| GET | `/` | API root |
| GET | `/config` | Server configuration |
| GET | `/stats` | Server statistics |
| GET | `/status` | Server status |
| GET | `/status.txt` | Status text |
| GET | `/status/influx` | InfluxDB metrics |
| GET | `/status/resources` | Resource usage |
| GET | `/status/test-event` | Test SSE event |
| GET/POST | `/data/organisations` | Organisations |
| GET/PUT/DELETE | `/data/organisations/{id}` | CRUD organisation |
| GET/POST | `/data/studios` | Studios |
| GET/PUT/DELETE | `/data/studios/{id}` | CRUD studio |
| GET/POST | `/data/project-status` | Project statuses |
| GET/PUT/DELETE | `/data/project-status/{id}` | CRUD project status |
| GET/POST | `/data/status-automations/` | Status automations |
| GET/PUT/DELETE | `/data/status-automations/{id}` | CRUD status automation |
| GET/POST | `/data/plugins` | Plugins |
| GET/PUT/DELETE | `/data/plugins/{id}` | CRUD plugin |
| GET/POST | `/data/subscriptions/` | Subscriptions |
| GET/PUT/DELETE | `/data/subscriptions/{id}` | CRUD subscription |
| GET/POST | `/data/salary-scales` | Salary scales |
| GET/PUT/DELETE | `/data/salary-scales/{id}` | CRUD salary scale |
| GET/POST | `/data/hardware-items` | Hardware items |
| GET/PUT/DELETE | `/data/hardware-items/{id}` | CRUD hardware item |
## Budgets & Scheduling
| Method | Path | Description |
|--------|------|-------------|
| GET/POST | `/data/projects/{id}/budgets` | Project budgets |
| GET | `/data/projects/{id}/budgets/time-spents` | Budget time spents |
| GET/PUT/DELETE | `/data/projects/{id}/budgets/{bid}` | CRUD budget |
| GET/POST | `/data/projects/{id}/budgets/{bid}/entries` | Budget entries |
| GET/PUT/DELETE | `/data/projects/{id}/budgets/{bid}/entries/{eid}` | CRUD entry |
| GET/POST | `/data/milestones/` | Milestones |
| GET/PUT/DELETE | `/data/milestones/{id}` | CRUD milestone |
| GET | `/data/projects/{id}/milestones` | Project milestones |
| GET/POST | `/data/schedule-items/` | Schedule items |
| GET/PUT/DELETE | `/data/schedule-items/{id}` | CRUD schedule item |
| GET | `/data/projects/{id}/schedule-items` | Project schedule items |
| GET | `/data/projects/{id}/schedule-items/task-types` | Schedule by task type |
| GET | `/data/projects/{id}/schedule-items/{tt_id}/asset-types` | By asset type |
| GET | `/data/projects/{id}/schedule-items/{tt_id}/episodes` | By episode |
| GET | `/data/projects/{id}/schedule-items/{tt_id}/sequences` | By sequence |
| GET/POST | `/data/production-schedule-versions` | Schedule versions |
| GET/PUT/DELETE | `/data/production-schedule-versions/{id}` | CRUD version |
| GET | `/data/production-schedule-versions/{id}/task-links` | Version task links |
| GET/POST | `/data/production-schedule-version-task-links` | Task links |
| GET/PUT/DELETE | `/data/production-schedule-version-task-links/{id}` | CRUD task link |
| POST | `/actions/production-schedule-versions/{id}/apply-to-production` | Apply schedule |
| POST | `/actions/production-schedule-versions/{id}/set-task-links-from-production` | Sync from prod |
| POST | `/actions/production-schedule-versions/{id}/set-task-links-from-production-schedule-version` | Sync from version |
## Media Files
### Pictures
| Method | Path | Description |
|--------|------|-------------|
| POST | `/pictures/preview-files/{id}` | Upload preview image |
| GET | `/pictures/originals/preview-files/{id}.png` | Original PNG |
| GET | `/pictures/originals/preview-files/{id}.{ext}` | Original (any ext) |
| GET | `/pictures/originals/preview-files/{id}/download` | Download original |
| GET | `/pictures/previews/preview-files/{id}.png` | Preview size |
| GET | `/pictures/thumbnails/preview-files/{id}.png` | Thumbnail |
| GET | `/pictures/thumbnails-square/preview-files/{id}.png` | Square thumbnail |
| GET | `/pictures/thumbnails/attachment-files/{id}.png` | Attachment thumbnail |
| GET/POST | `/pictures/thumbnails/persons/{id}` | Person avatar |
| GET/POST | `/pictures/thumbnails/persons/{id}.png` | Person avatar PNG |
| GET/POST | `/pictures/thumbnails/projects/{id}` | Project thumbnail |
| GET/POST | `/pictures/thumbnails/projects/{id}.png` | Project thumbnail PNG |
| GET/POST | `/pictures/thumbnails/organisations/{id}` | Org thumbnail |
| GET/POST | `/pictures/thumbnails/organisations/{id}.png` | Org thumbnail PNG |
| POST | `/pictures/preview-background-files/{id}` | Upload BG file |
| GET | `/pictures/preview-background-files/{id}.{ext}` | Get BG file |
| GET/POST | `/pictures/thumbnails/preview-background-files/{id}.png` | BG thumbnail |
### Movies
| Method | Path | Description |
|--------|------|-------------|
| GET | `/movies/originals/preview-files/{id}.mp4` | Original movie |
| GET | `/movies/originals/preview-files/{id}/download` | Download movie |
| GET | `/movies/low/preview-files/{id}.mp4` | Low-res movie |
| GET | `/movies/tiles/preview-files/{id}.png` | Movie tile strip |

View File

@ -0,0 +1,183 @@
# Kitsu Event Types
Events are emitted in real-time via Server-Sent Events (SSE) and stored in the event log.
## Listening to Events
```python
import gazu
gazu.set_host("https://kitsu.mystudio.com/api")
gazu.set_event_host("https://kitsu.mystudio.com") # no /api suffix
gazu.log_in("user@studio.com", "password")
event_client = gazu.events.init()
def handler(data):
print(data)
gazu.events.add_listener(event_client, "task:status-changed", handler)
gazu.events.run_client(event_client) # blocks
```
Run the listener in a separate thread since `run_client()` blocks.
## Event Naming Convention
Pattern: `entity_type:action`
Entity type is the model name lowercased with spaces replaced by hyphens.
## Callback Data
The callback `data` dict always includes:
- The entity ID (e.g., `asset_id`, `shot_id`, `task_id`)
- `project_id` when relevant
## Complete Event List
### Assets
- `asset:new` — Asset created
- `asset:update` — Asset updated
- `asset:delete` — Asset deleted
- `asset:new-link` — Asset linked to another entity
- `asset:remove-link` — Asset link removed
- `asset:casting-update` — Asset casting changed
- `asset-type:new` — Asset type created
- `asset-type:update` — Asset type updated
- `asset-type:delete` — Asset type deleted
- `asset-instance:new` — Asset instance created
- `asset-instance:update` — Asset instance updated
- `asset-instance:delete` — Asset instance deleted
### Shots / Sequences / Episodes / Scenes
- `shot:new` — Shot created
- `shot:update` — Shot updated
- `shot:delete` — Shot deleted
- `shot:casting-update` — Shot casting changed
- `sequence:new` — Sequence created
- `sequence:update` — Sequence updated
- `sequence:delete` — Sequence deleted
- `episode:new` — Episode created
- `episode:update` — Episode updated
- `episode:delete` — Episode deleted
- `scene:new` — Scene created
- `scene:update` — Scene updated
- `scene:delete` — Scene deleted
### Tasks
- `task:new` — Task created
- `task:update` — Task updated
- `task:delete` — Task deleted
- `task:assign` — Person assigned to task
- `task:unassign` — Person unassigned from task
- `task:status-changed` — Task status changed (via comment)
- `task:to-review` — Task sent for review
- `task-type:new` — Task type created
- `task-type:update` — Task type updated
- `task-type:delete` — Task type deleted
- `task-status:new` — Task status created
- `task-status:update` — Task status updated
- `task-status:delete` — Task status deleted
### Comments
- `comment:new` — Comment posted
- `comment:update` — Comment edited
- `comment:delete` — Comment removed
- `comment:reply` — Reply added to comment
- `comment:acknowledge` — Comment acknowledged
### Files
- `preview-file:new` — Preview file uploaded
- `preview-file:update` — Preview file updated
- `working-file:new` — Working file created
- `output-file:new` — Output file created
- `output-file:update` — Output file updated
- `output-file:delete` — Output file deleted
### Persons
- `person:new` — Person created
- `person:update` — Person updated
- `person:delete` — Person deleted
### Projects
- `project:new` — Project created
- `project:update` — Project updated
- `project:delete` — Project deleted
### Edits & Concepts
- `edit:new` — Edit created
- `edit:update` — Edit updated
- `edit:delete` — Edit deleted
- `concept:new` — Concept created
- `concept:update` — Concept updated
- `concept:delete` — Concept deleted
### Playlists
- `playlist:new` — Playlist created
- `playlist:update` — Playlist updated
- `playlist:delete` — Playlist deleted
### Notifications
- `notification:new` — Notification created
- `notification:update` — Notification updated
- `notification:delete` — Notification deleted
### Chat
- `chat:new` — Chat created
- `chat:update` — Chat updated
- `chat:delete` — Chat deleted
- `chat-message:new` — Message sent
- `chat-message:update` — Message edited
- `chat-message:delete` — Message deleted
### News
- `news:new` — News item created
- `news:update` — News item updated
- `news:delete` — News item deleted
### Entity Links
- `entity-link:new` — Entity link created
- `entity-link:delete` — Entity link removed
### Budget
- `budget:new` — Budget created
- `budget:update` — Budget updated
- `budget:delete` — Budget deleted
- `budget-entry:new` — Budget entry created
- `budget-entry:update` — Budget entry updated
- `budget-entry:delete` — Budget entry deleted
### Schedule
- `schedule-item:new` — Schedule item created
- `schedule-item:update` — Schedule item updated
- `schedule-item:delete` — Schedule item deleted
- `milestone:new` — Milestone created
- `milestone:update` — Milestone updated
- `milestone:delete` — Milestone deleted
### Time Tracking
- `time-spent:new` — Time entry created
- `time-spent:update` — Time entry updated
- `time-spent:delete` — Time entry deleted
### Build Jobs
- `build-job:new` — Build job created
- `build-job:update` — Build job updated
- `build-job:delete` — Build job deleted
## Reading Event History
```python
# Recent events
events = gazu.client.get("data/events/last?page_size=100")
# Filter by date
events = gazu.client.get("data/events/last?page_size=100&before=2024-02-01&after=2024-01-01")
# File events only
events = gazu.client.get("data/events/last?page_size=100&only_files=true")
# Login logs
logs = gazu.client.get("data/events/login-logs/last")
```