Projects

By default, a generation created from the API isn’t filed under anything in particular. Projects let you group related generations and assets together so they appear under one project in the Studio — and so you can list them back out from the API. It’s a two-way road: create a project from the API, attach work to it, and it’s visible in the Studio UI; create a project in Studio, and the API can attach to it too.

A project is lightweight — only a name is required.

Create a project

POST /v2/projects returns the new project’s id. visibility defaults to USER (visible only to the key owner) and mode to CREATOR; both are optional.

$curl -X POST https://api.sync.so/v2/projects \
> -H "x-api-key: $SYNC_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{ "name": "My API Project" }'

Attach generations and assets

Pass the project’s id as projectId when you create a generation or register an asset. The field is optional on both endpoints — omit it and the work simply isn’t grouped under a project.

$curl -X POST https://api.sync.so/v2/generate \
> -H "x-api-key: $SYNC_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{
> "model": "lipsync-2",
> "projectId": "612bb64a-e7f4-40c1-977b-3e9797845637",
> "input": [
> { "type": "video", "url": "https://assets.sync.so/docs/example-video.mp4" },
> { "type": "audio", "url": "https://assets.sync.so/docs/example-audio.wav" }
> ]
> }'

The generation and asset responses echo back the projectId they were filed under (or null when none was given).

projectId must reference a project in your organization. If it doesn’t (wrong id, or a project from another org), the create request is rejected with 422 Unprocessable Entity — the generation or asset is not created. A missing or null projectId is always fine.

Attach an existing asset

If an asset already exists — say, one you uploaded earlier or picked from your library — you can attach it to a project after the fact with POST /v2/projects/{id}/assets, passing the asset’s id as assetId in the body. The asset must belong to your organization. This is the counterpart to setting projectId at creation time: use it to file work you didn’t group up front.

cURL
$curl -X POST https://api.sync.so/v2/projects/612bb64a-e7f4-40c1-977b-3e9797845637/assets \
> -H "x-api-key: $SYNC_API_KEY" \
> -H "Content-Type: application/json" \
> -d '{ "assetId": "8f14e45f-ceea-467d-9a1b-3e4d5c6f7a8b" }'

The call is idempotent — attaching an asset that is already linked to the project succeeds without creating a duplicate — and returns 204 No Content on success. A project or asset that isn’t in your organization returns 404 Not Found.

See it in Studio

Once attached, generations and assets show up under the project in the Studio. This works in both directions — a project you create in Studio can be targeted from the API by its id, and a project you create from the API appears in Studio. Deleting a project does not delete the generations or assets that were attached to it; they simply stop being grouped under it.

Manage projects

ActionEndpoint
CreatePOST /v2/projects
ListGET /v2/projects
Get oneGET /v2/projects/{id}
Attach an assetPOST /v2/projects/{id}/assets
UpdatePATCH /v2/projects/{id}
DeleteDELETE /v2/projects/{id}

GET /v2/projects is cursor-paginated (limit, cursor) and supports searchQuery (by name) and sortBy (updatedAt or name). PATCH only changes the fields you send.

$curl https://api.sync.so/v2/projects?limit=10 \
> -H "x-api-key: $SYNC_API_KEY"