Skip to content

Legacy

These endpoints live under /api/v1 and cover clip metadata only. The primary API reference is API (/api/v2), which adds jobs, single-document routes, and the wire format used there.

Requests to /api/v1/.../jobs/... return 404; job metadata is only available under /api/v2.

Migrating from v1 to v2

Topic v1 v2
Base path (same host) /api/v1/... /api/v2/... — see API
Clips GET shape data.message is an object keyed by clip name data is a sorted array of clip objects
Clips wire keys Mixed: many stored lowercase names in JSON (e.g. reelname, librarypath) camelCase only (e.g. reelName, libraryPath); unknown fields → 400
Clips PATCH {"data":[{...}]}; permissive Same top-level {"data":[...]} pattern, but camelCase fields only; duplicates in one request → 400; response includes updated, projectId, names
Single clip by URL Use bulk endpoints only GET / PATCH/clips/{project}/{clip_name}/{token}
Jobs Not supported on v1 GET / PATCH/jobs/{project}/{token} (bulk) and …/jobs/{project}/{job_id}/{token} (single) — see API
API tokens Same tokens; clip read/write as today Same token flags: Read / Write / Upload; read covers GET jobs, write covers PATCH jobs
Upload (signed URLs) GET https://odailies.com/api/v1/upload/{project_id}/{token}/{path} — see below After moving clips/jobs to the current API, see API for how upload signing is documented there.

After migration, follow API for clips (arrays, camelCase), jobs, and any upload URL changes you adopt with the newer contract.


Clip metadata (v1)

Endpoint: /api/v1/clips/{project_id}/{token} (or legacy paths where the URL ends with /{project_id}/{token} and the segment before the project is not jobs — same behavior as before).

Get clip metadata

GET /api/v1/clips/{project_id}/{token}

Retrieves metadata for all clips in the project.

Response:

{
  "data": {
    "message": {
      "clip_name": {
        "name": "string",
        "scene": "string",
        "shot": "string",
        "take": "string",
        "description": "string",
        "circled": boolean,
        "rating": number,
        "inPoint": number,
        "camera": "string",
        "timecode": "string",
        "fps": number,
        "date": "string",
        "duration": number,
        "reelname": "string",
        "whitepointkelvin": number,
        "whitepointccshift": number,
        "shutter": number,
        "filter": "string",
        "ndfilter": "string",
        "lens": "string",
        "focallength": number,
        "focusdistance": number,
        "asa": number,
        "sensorFps": number,
        "fStop": number,
        "tStop": number,
        "filesize": number,
        "librarypath": "string"
      }
    }
  }
}

The date field must use the yyyyMMdd format (e.g. 20260422), same as API v2.

Update clip metadata

PATCH /api/v1/clips/{project_id}/{token}
Content-Type: application/json
{
  "data": [
    {
      "name": "A001C001_260422_R3CK",
      "scene": "22",
      "shot": "4",
      "take": "1"
    },
    {
      "name": "A001C002_260422_R3CK",
      "scene": "22",
      "shot": "4",
      "take": "2",
      "circled": true
    }
  ]
}

Updates metadata for specified clips. Only the fields you include will be updated. Each clip in the list must include a name field to identify the clip to update.

Upload (signed URLs)

GET https://odailies.com/api/v1/upload/{project_id}/{token}/{path}

Returns JSON with a time-limited url (send the file body with PUT to that URL), expiresAt (ISO 8601, UTC), and the same semantics as v2 upload. Requires the same API token upload permission as other tools. The path value follows the uploading directory layout (for example _graded/… or _thumbnails/ClipName.jpg). {path} may include slashes.


Code example (Python, v1 only)

import requests

class oDailiesClientV1:
    """Legacy v1 clips client (map GET, stored field names on the wire)."""

    def __init__(self, project_id: str, token: str):
        self.project_id = project_id
        self.token = token
        self.base_url = "https://odailies.com/api/v1"
        self.clips_url = f"{self.base_url}/clips/{self.project_id}/{self.token}"

    def get_clips(self) -> dict:
        response = requests.get(self.clips_url)
        response.raise_for_status()
        return response.json()["data"]["message"]

    def update_clip(self, clip_name: str, metadata: dict):
        response = requests.patch(
            self.clips_url,
            json={"data": [{"name": clip_name, **metadata}]},
            headers={"Content-Type": "application/json"},
        )
        response.raise_for_status()
        return response.json()

    def update_clips(self, clips: list):
        response = requests.patch(
            self.clips_url,
            json={"data": clips},
            headers={"Content-Type": "application/json"},
        )
        response.raise_for_status()
        return response.json()

A Python example for /api/v2 is on API.