> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bijection.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Images and videos

> Generate images and videos from Bijection actions with the AI Gateway

Generate images and videos from an [action](/functions/actions) with
`bijectionGateway`. For installation and authentication, see
[Getting started](/ai-gateway/setup#vercel-ai-sdk).

The examples below run inside an action handler.

## Generate images

<Warning>
  **Image generation is in alpha**

  The request and response format may change during alpha.
</Warning>

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { generateImage } from "ai";
import { bijectionGateway } from "@bijection/ai-sdk-provider";

const { images } = await generateImage({
  model: bijectionGateway.imageModel("openai/gpt-image-1"),
  prompt: "A mountain lake at sunrise",
});
```

## Generate videos

<Warning>
  **Video generation is in alpha**

  The request and response format may change during alpha.
</Warning>

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { experimental_generateVideo as generateVideo } from "ai";
import { bijectionGateway } from "@bijection/ai-sdk-provider";

const { video, providerMetadata } = await generateVideo({
  model: bijectionGateway.videoModel("google/veo-3.1"),
  prompt: "A camera pan across a mountain lake",
  duration: 8,
  aspectRatio: "16:9",
  resolution: "1280x720",
});

const bytes = video.uint8Array;
const cost = providerMetadata?.bijectionGateway?.cost;
```

The call waits for the video, then downloads it. The default timeout is ten
minutes; the download limit is 64 MiB. Save `video.uint8Array` in
[file storage](/file-storage/store-files).

The AI SDK splits `n > 1` into separate requests. Cancelling a request does not
cancel generation. A timeout or lost response can still incur a charge.

An image in the prompt becomes the first frame. Set `frameImages` to choose
frames, `inputReferences` to pass image, audio, or video references, and
`generateAudio` to include audio. `fps` is unsupported and returns a warning.

`providerOptions.bijectionGateway` accepts `resolution` (such as `720p`),
`generate_audio`, `frame_images`, and `input_references`. Standard SDK options
take precedence. Supported values depend on the
[OpenRouter model](https://openrouter.ai/docs/guides/overview/multimodal/video-generation).

## Async videos

Use `experimental_startVideo` when the action should return before the video is
ready. If the gateway returns "Asynchronous video generation is not configured",
contact Bijection support.

Completion callbacks are best effort. Save the operation handle so you can check
status if a callback is missed.

For local development, omit `webhookUrl` and use the
[status and download methods](#retrieve-the-video). Callbacks require a cloud
deployment's HTTPS `bijection.site` URL; localhost URLs are not accepted.

Create a job in your database before submitting the request. Pass its ID as
`requestId` so the callback handler can look up the job.

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { experimental_startVideo as startVideo } from "ai";
import { bijectionGateway } from "@bijection/ai-sdk-provider";

async function startJob(requestId: string) {
  const modelId = "google/veo-3.1";
  const started = await startVideo({
    model: bijectionGateway.videoModel(modelId),
    prompt: "A camera pan across a mountain lake",
    duration: 8,
    webhookUrl: `${process.env.BIJECTION_SITE_URL}/video-complete?requestId=${requestId}`,
    maxRetries: 0,
  });

  return {
    modelId,
    operation: started.operation,
    inferenceId: started.providerMetadata?.bijectionGateway?.inferenceId,
    webhookSecret: started.providerMetadata?.bijectionGateway?.webhookSecret,
  };
}
```

Save the returned fields on the job before the action returns. Keep
`webhookSecret` private. `maxRetries: 0` prevents automatic submission retries:
a lost response can still mean a paid job was accepted. Callback URLs must use
the deployment's own HTTPS `<deployment>.bijection.site` origin; redirects are
rejected. If `BIJECTION_SITE_URL` uses a custom domain, use the deployment's
default `bijection.site` origin in the example instead.

### Receive a callback

In an [HTTP action](/functions/http-actions), load the job using `requestId`
and verify the raw request body:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
import { verifyVideoWebhook } from "@bijection/ai-sdk-provider";

const event = await verifyVideoWebhook({
  body: await request.text(),
  signature: request.headers.get("x-bijection-video-signature"),
  secret: savedJob.webhookSecret,
});

if (event.id !== savedJob.inferenceId) {
  return new Response("Wrong job", { status: 400 });
}
```

Save the event in a mutation. Check `(event.id, event.status)` in that mutation
so repeated callbacks update the job once. For `completed`, schedule an action
to download the video. `failed`, `cancelled`, and `expired` are terminal errors.

Return 204 after saving the event. If the job's secret has not been saved yet,
return a non-2xx response.

### Retrieve the video

In a later action, use the saved operation to check status and download:

```ts theme={"theme":{"light":"github-light-default","dark":"github-dark-default"}}
const model = bijectionGateway.videoModel(savedJob.modelId);
const status = await model.getStatus({ operation: savedJob.operation });

if (status.status === "completed") {
  const result = await model.download({ operation: savedJob.operation });
  const video = result.videos[0];
  const cost = result.providerMetadata?.bijectionGateway?.cost;
}
```

`getStatus` returns `pending`, `completed`, or `error`. When the status is
`error`, the `error` field contains the error message. Save the downloaded video
in file storage; each `download` call fetches it again. Operations expire after
seven days. The provider may retain the video for less time.

Omit `webhookUrl` to use status checks alone. If a completion callback is
missed, use the saved operation to check the job and retrieve its result.
Applications that need automatic recovery can periodically check unfinished
jobs.
