Integrations
Odori connects to Vercel AI Gateway for images and video, Quiver for SVG artwork, and ElevenLabs for audio. Generation saves assets in your project. Preview and export use those saved files without a provider connection.
Connect an account
Use your provider's API key. You do not need an Odori login. Choose the Studio form or the CLI; both use the same saved credentials on your machine.
| Provider | What it enables | Environment variable |
|---|---|---|
| Vercel AI Gateway | Images and video | AI_GATEWAY_API_KEY |
| Quiver | SVG generation and vectorization | QUIVER_API_KEY |
| ElevenLabs | Music, sound effects, and speech | ELEVENLABS_API_KEY |
| Vercel Blob | Uploading local start images for video | BLOB_READ_WRITE_TOKEN |
Connect only the services you use. Follow the provider's instructions to create a key and enable the required model access.
Connect in Studio
- Run
odori devin your project. - Open Settings → Integrations, or select Connect provider in Assets.
- Select Connect beside the provider.
- Paste its API key into the password field and select Save.
- Return to Assets, choose the provider and model, then review your generation.
Stored keys are not displayed again. To replace a saved key, select Disconnect, then connect with the new key. Disconnecting removes the saved credential; it does not revoke the key at the provider.
If the connection comes from an environment variable, update that variable and restart Studio. Saving another key cannot override it.
Connect from the CLI
Set the relevant variable in the shell that runs Odori:
export AI_GATEWAY_API_KEY="your_gateway_key"
export QUIVER_API_KEY="your_quiver_key"
export ELEVENLABS_API_KEY="your_elevenlabs_key"
odori integrations --jsonKeys saved in Studio live in a permission-restricted file under ~/.config/odori/, outside your project. This file is not encrypted. Environment variables take precedence. Studio reports connection status without returning stored keys. A saved key is not a guarantee that a model is available to your account.
These variables apply to processes started from that shell. To save a key for later CLI and Studio sessions, read it from an environment variable:
odori integrations connect vercel --provider vercel --key-env AI_GATEWAY_API_KEYThe command reads the variable's value and saves it on this machine. It does not take a literal key as a command argument. Run odori integrations --json to check connection status without printing credentials.
Use multiple accounts
To separate work and personal accounts, create a named connection from an existing environment variable:
odori integrations connect work-gateway \
--provider vercel --key-env WORK_GATEWAY_KEYChoose that connection with --connection work-gateway. Generation is billed to the selected account. Odori does not switch to an Odori-managed billing account.
Choose a model
odori models
odori models --provider vercel --live --json
odori models --provider quiver --liveCurated defaults are Nano Banana Pro for images, Seedance 2.5 for video, Arrow 1.1 for SVG, and the existing ElevenLabs audio models. Availability depends on your account and the provider's current catalog. Custom Gateway image and video IDs must appear in live discovery. Image editing uses the curated Gemini image routes; discovering a model does not imply support for every operation.
Set a personal default:
odori integrations default --operation image.generate \
--provider vercel --model google/gemini-3.1-flash-imageProject defaults override personal defaults, and command flags override both:
import {defineConfig} from "@odori/cli";
export default defineConfig({
media: {
defaults: {
"image.generate": {
provider: "vercel",
model: "google/gemini-3-pro-image",
connection: "work-gateway",
},
},
},
});Import existing media
Import a file without calling a provider:
odori image import ./artwork.svg --name artwork
odori video import ./footage.mp4 --name footageStudio Assets also accepts uploads under Import existing media. Browser uploads are limited to 12 MB; CLI imports support up to 256 MB. Imports are copied into the local library, inspected, and available for approval, editing, or animation.
Images and vectors
odori image generate "Editorial photograph of a coastal bookshop" \
--name bookshop --aspect-ratio 16:9 --resolution 1K --dry-run
odori image generate "Editorial photograph of a coastal bookshop" \
--name bookshop --aspect-ratio 16:9 --resolution 1K
odori image edit public/bookshop.png \
--prompt "Keep the composition, make the light warmer" --name warm-bookshop
odori image generate "A simple geometric constellation emblem" \
--provider quiver --format svg --name emblem
odori image vectorize public/emblem.png --name vector-emblemUse --references with comma-separated project paths or public HTTPS URLs for supported image models. Local references must be inside the project. A maximum of four additional references is accepted. Uploaded references and prompts leave your machine when generation runs.
Quiver SVGs are sanitized before preview. Odori removes scripts, event handlers, unsafe external references, and unsupported elements, while preserving shapes, groups, gradients, and scoped IDs. The original is retained in .odori/media-originals/. Inspect the artwork before using it; generated SVG does not automatically become a semantic React component.
Video
odori video generate "A slow push toward the bookshop entrance" \
--image public/bookshop.png --duration 6 \
--resolution 1280x720 --name bookshop-shot --no-waitGateway's asynchronous video API needs hosted image references. For a local start image, connect Vercel Blob in Settings or set BLOB_READ_WRITE_TOKEN. Odori uploads it to your public Blob store. These uploads currently remain in your store until you delete them; do not delete one while its generation is running. You can instead pass an existing public HTTPS image URL.
This release supports text-to-video and one start image. Multiple video references, extension, and video editing are not exposed. Unsupported settings fail before submission where the local model contract can determine them; providers still validate model-specific options.
Audio
odori audio generate "Warm ambient instrumental, no vocals" \
--type music --duration 30 --name background
odori audio generate "A soft confirmation chime" \
--type sfx --duration 2 --name confirmation
odori audio generate "Introducing our new editor." \
--type speech --name narrationSpeech includes a .narration.json file with word timing. Use the saved asset URL with Odori's declarative Audio component. Choose a voice using --voice. Existing audio import and legacy audio generate --output workflows remain available for brand registration and explicit loudness preparation.
<Audio src="/media/gen-example/background.mp3" loop />Use the actual path returned by generation. Generated video's audio is inspected, but is not automatically mixed into another composition.
Review in Studio
In Assets, choose an operation, account, model, and prompt. Upload a reference if needed, then select Review generation. The review identifies the account, model, and data being sent. Generate with my account submits the request.
Completed assets have local previews, downloads, metadata, approval controls, and composition code you can copy into your scene. Variation preserves the source settings and creates a new version; Edit and Animate use the selected image as their input. Existing usages are never silently replaced. The composition-code action also reports direct usages found in video source. Indirect or dynamically constructed references may not be found.
Approval records your creative choice; it does not change provider billing. A generated result can be billable even if you choose not to use it.
Template media recipes
Recipes give a template an explicit asset brief, dimensions, brand notes, and a fallback. They populate the Studio form; they do not generate during playback or change your scene automatically.
import {defineConfig} from "@odori/cli";
export default defineConfig({
media: {
recipes: [
{
id: "editorial-cover",
title: "Editorial cover photograph",
fallback: "/images/cover.jpg",
brandNotes: "Warm natural light, restrained colors, space for a headline.",
request: {
operation: "image.generate",
prompt: "A quiet bookshop in Lisbon, viewed from the street",
aspectRatio: "16:9",
resolution: "1K",
name: "editorial-cover",
},
},
{
id: "product-emblem",
title: "Product emblem",
fallback: "/images/emblem.svg",
brandNotes: "One accent color. No text. Simple geometry.",
request: {
operation: "image.generate",
provider: "quiver",
format: "svg",
prompt: "An abstract constellation mark for a developer tool",
name: "product-emblem",
},
},
],
},
});Keep UI, typography, charts, and timing in editable React components. Generate independent artwork or footage, review a still first, and then animate an approved image if needed. Replace the fallback URL in your component only after review.
Jobs and recovery
odori jobs --json
odori jobs get gen-JOB_ID --json
odori jobs collect gen-JOB_ID --json
odori jobs cancel gen-JOB_IDUse the actual ID returned by generation. --no-wait starts a background collector. It can continue after Studio closes, but cannot run while your computer is asleep. jobs collect resumes polling or downloads an existing result without generating again.
If the provider may have accepted a submission but Odori did not receive its ID, the job becomes uncertain. Check the provider's history before creating another job. Odori never silently resubmits an uncertain request. Cancellation is only offered before submission because these adapters cannot confirm cancellation afterward.
Assets and provenance live under public/media/. Job recovery data lives under .odori/generations/. Keep recovery data until work finishes. Saved assets continue to work after disposable job data is removed. Review prompts and provenance before publishing the project, since they are saved alongside the media.
Options and cost
--options path.json supplies provider-specific JSON. Gateway options use provider namespaces, for example google; routing overrides and credential fields are rejected. Quiver accepts its documented generation or vectorization controls. Do not put API keys in project configuration or options.
--dry-run validates inputs without submitting generation. It may contact a provider to discover a custom model. Exact generation pricing is currently shown as unknown. --max-cost rejects submission because these adapters cannot guarantee a final upper bound. Configure spending controls in the provider account.
Managed Odori credits and fal are not part of local BYOK.