Opening Final Frame
Verifying your credentialsEstablishing an encrypted sessionPreparing your workspace
Secured by WorkOS
This is taking longer than usual. Your connection may be slow.

CLI and SDK

Two thin layers over the same API, for people and agents who would rather not write the requests by hand. Both are in the platform's repository today and will be published as packages at launch.

ff, the command line

No dependencies. Every command is a call to /v1; --json prints the answer as it came, --all follows every page, and ff call reaches any route the OpenAPI document lists.

ff login --key <api key> --base https://app.final-frame.com/api
ff whoami
ff projects --direction outbound
ff works --territory GB --from 2027-01-01 --to 2027-12-31
ff check --identity "eidr:10.5240/..." --right svod --territory GB --from 2027-01-01
ff work-order create <projectId> --name "Subtitle the trailer" --kind subtitling
ff config export > final-frame.json
ff config apply final-frame.json
ff call GET /v1/projects --json

The key lives in ~/.config/final-frame/config.json (mode 600) or in FF_API_KEY; FF_API_BASE picks the environment. ff --help lists everything.

Configuration as code

An organisation's set-up is one document: delivery specs, house formats, the metadata schema and every taxonomy. GET /v1/config exports it; PUT /v1/config applies it, upserting specs by name and taxonomy terms by key, replacing the formats and the schema when given, and never deleting. Keep it in your own repository, copy a set-up between organisations with two commands, or let an agent set a new one up.

TypeScript SDK

import { createClient } from '@finalframe/sdk';

const ff = createClient({ apiKey: process.env.FF_API_KEY!, baseUrl: 'https://app.final-frame.com/api' });
for await (const project of ff.projects.all()) console.log(project.reference, project.name);

const answer = await ff.rights.availability({ identity, right: 'svod', territory: 'GB', from: '2027-01-01' });
const order = await ff.workOrders.create(projectId, { name: 'Subtitle the trailer', kind: 'subtitling' });

Every list has list() for one page and all() for every page. Writes are idempotent: pass idempotencyKey, or the client derives one from the body. Errors are FinalFrameError with the status, the code, the message and the scope a 403 named. A Python SDK, generated from the OpenAPI document, follows at launch.