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

> ## Agent Instructions
> Phaseo Gateway base URL: https://api.phaseo.app/v1. Send `Authorization: Bearer $PHASEO_API_KEY` with every request.
> Model IDs look like `provider/model`, for example `openai/gpt-6-astra`. Do not guess IDs: list them with `GET /v1/models` or check https://phaseo.app/models. `phaseo/free` routes to an available free model and needs no wallet balance.
> For new text integrations prefer `POST /v1/responses`. `POST /v1/chat/completions` (OpenAI format) and `POST /v1/messages` (Anthropic format) suit existing code.
> The full API contract is https://phaseo.app/docs/openapi/v1/openapi.yaml. Official SDKs: `@phaseo/sdk` (TypeScript) and `phaseo` (Python), plus Go, C#, PHP, Ruby and Rust.
> Search these docs over MCP at https://phaseo.app/docs/mcp, and install Phaseo skills with `npx skills add https://phaseo.app/docs`. If a page is wrong or out of date, report it with the MCP `submit_feedback` tool.
> Manage Phaseo accounts with the `phaseo` CLI (`npm install -g @phaseo/cli`, then `phaseo login` or `phaseo login --device-code`), the `/v1` Management API or the MCP server at `https://mcp.phaseo.app/mcp?access=manage`. Do not send users to the dashboard for account tasks. A person is still needed for sign-up, approving a sign-in, paying the first top-up on the checkout link that `phaseo credits add` returns when no card is saved, confirming each saved-card top-up from the emailed link, and account security (password, MFA, passkeys). Create API keys with `phaseo keys create --name <name> --json`; never guess one. Credit top-ups need `phaseo login --scopes billing:write` first. Task map: https://phaseo.app/docs/v1/developers/manage-from-an-agent.md.

# Video and batch jobs

> Track asynchronous jobs, receive webhooks, and pass provider-specific video options.

> [!NOTE]
>
> The Video API and Batch API are invite-only beta previews for selected workspaces. Check **Settings → Feature Preview** for availability. Access is managed per workspace; enabling a personal web preference does not grant API access. Normal model usage charges apply.

Video generation and batch processing return a job before the work finishes. Persist its `id` and use the returned `polling_url` to recover its latest state. A successful create response does not mean generation or batch processing has completed.

During the beta, start with small requests and an API key spending limit. Provider and model capabilities vary; reference inputs, cancellation and output retention depend on the selected provider. Keep your own copy of completed outputs before they expire.

## Receive updates

Attach a webhook endpoint belonging to your workspace when creating either kind of job:

```json theme={null}
{
  "webhook": {
    "endpoint_id": "YOUR_ENDPOINT_ID",
    "events": ["job.status_changed", "job.completed", "job.failed", "job.cancelled", "job.expired"]
  }
}
```

Phaseo reconciles provider status and sends customer notifications. Providers that require polling, including Anthropic message batches, can still produce customer webhooks. A webhook delivery failure is separate from a generation or batch failure.

Endpoint subscriptions can target Batch and Video events independently. Use namespaced event types such as `batch.completed` or `video.failed`; generic `job.*` event types remain supported and subscribe to the matching phase for both job types.

Verify `x-phaseo-signature` using the endpoint secret: the signature is the hexadecimal HMAC-SHA256 of `x-phaseo-timestamp`, a literal period, and the **unmodified request body**. Check timestamp freshness, deduplicate `x-phaseo-event-id`, and acknowledge accepted deliveries with a successful HTTP response. Deliveries can be retried or arrive out of order; retrieve the job before applying a conflicting state change.

After saving an endpoint, use **Send test event** in Settings to deliver a signed `webhook.test` payload. Test deliveries make one attempt and are not retried or added to job delivery history.

Treat `completed`, `failed`, `cancelled`, and `expired` lifecycle states as terminal. Keep a polling recovery path even when using webhooks.

```mermaid theme={null}
flowchart TD
  newJob["Create a video or batch job"] --> store["Store id and polling_url"]
  store --> waiting["Wait for an update"]
  waiting -->|"Webhook event"| terminal{{"Terminal state?"}}
  waiting -->|"Poll polling_url"| terminal
  terminal -->|"No"| waiting
  terminal -->|"completed"| fetchOut["Fetch the outputs or results"]
  terminal -->|"failed / cancelled / expired"| outcome["Handle the outcome"]
```

For each event, Phaseo makes one initial delivery attempt. A successful 2xx response ends delivery; no retries are needed. Failed deliveries receive up to three retries, scheduled after 1, 5, and 15 minutes. Background sweeps process eligible retries, so actual delivery can be later than the scheduled time. Each attempt records its number, time, HTTP status, error and next retry time. After the fourth unsuccessful attempt, delivery is marked permanently failed. Receivers must still deduplicate events: a lost acknowledgement or worker interruption can make delivery uncertain.

## View job and request logs

In **Settings → Usage → Logs**, use **Requests** for inference request details, **Video** for video lifecycles, and **Batch** for batch jobs and row results. Video and Batch detail views include billing status, provider attempts, and webhook attempts. A job can complete successfully while its webhook delivery fails.

Video submission reserves credit before contacting the provider. A timeout with no task ID retains the reservation for reconciliation; it is not evidence of a failed generation. If a paid Video or Batch reservation unexpectedly prices at zero after successful work, billing remains open with `unexpected_zero_cost` for investigation. A zero-cost create response alone is normal for asynchronous generation.

## Video inputs

### Understand video pricing

Video prices depend on the provider and model. A price per second must be multiplied by the billable duration; a price per clip applies only to its specified duration and resolution. Multiple outputs and chargeable reference inputs can increase the total.

LTX text/image generation bills output seconds, while audio-to-video bills input-audio seconds. BytePlus Seedance uses video tokens, with different rates when a reference video is present. MiniMax Hailuo V1 uses fixed-duration clip prices; H3 uses seconds and can charge for reference inputs. Check the selected provider's pricing dimensions rather than interpreting a headline price as the cost of a whole request.

Reservations are estimates held before submission. Final billing uses the job's billable usage; unused reserved credit is released after reconciliation. A provider's supported resolution or option does not guarantee that it is available in the beta.

Use `seconds` or `duration` for output duration. If both are present, they must agree. Use `resolution` with `aspect_ratio`, or a pixel `size` such as `1280x720`.

Use `frame_images` for explicit first and last frames:

```json theme={null}
{
  "frame_images": [
    {
      "type": "image_url",
      "frame_type": "first_frame",
      "image_url": { "url": "https://example.com/start.png" }
    }
  ],
  "input_references": [
    {
      "type": "image_url",
      "role": "reference",
      "image_url": { "url": "https://example.com/character.png" }
    }
  ]
}
```

Reference URLs must use HTTPS. Specify `role: "reference"` explicitly for reference-only images: legacy requests without `frame_images` interpret the first unlabelled image as a first frame. Do not combine `frame_images` with first/last-frame roles in `input_references` or with `input_reference`.

Video and audio references use `type: "video_url"` or `"audio_url"` and `media_url: { "url": "https://..." }`. Models and providers support different combinations. Where reference duration affects pricing, supply `input_video_duration` and `input_audio_duration` in seconds.

## Provider options

Keep model, duration, resolution, audio generation, input media, and output count in canonical fields. Pass provider-specific extensions under the canonical provider ID:

```json theme={null}
{
  "provider_options": {
    "atlascloud": { "watermark": false, "output_format": "mp4" },
    "byteplus": { "camera_fixed": true }
  }
}
```

Only the selected provider's options are forwarded. Options do not select a provider; use the `provider` routing configuration for that. Do not combine `provider_options` with legacy `provider_params`. Nested options cannot override gateway-controlled billing or callback fields.

| Provider | Example native extensions | Reference |
| - | - | - |
| AtlasCloud Seedance 2.5 | `watermark`, `output_format`, `return_last_frame`, `omni_reference_task_type` | [Model API](https://www.atlascloud.ai/models/bytedance/seedance-2.5/reference-to-video) |
| Novita Seedance 1.5 | `watermark`, `camera_fixed`, `fps` (24), `service_tier` (`default`) | [Unified video API](https://docs.novita.ai/api-reference/reference-unified-video-generation) |
| BytePlus Seedance | `camera_fixed` | Check the selected model's provider contract before use. |
| MiniMax V1 | `fast_pretreatment`; use canonical `enhance_prompt` for prompt optimization | [Video API](https://platform.minimax.io/docs/api-reference/video-generation-t2v) |

AtlasCloud Seedance uses native `resolution`, `ratio`, and `last_image` fields. Its reference-to-video variant receives ordered image, video, and audio references. Automatic-duration editing (`duration: -1`) is not supported by the gateway's fixed-duration reservation contract. Provider model availability and pricing must be configured before a model can be routed; a provider option does not enable an unavailable model.

MiniMax H3 uses V2: 4–15 whole seconds at `768P` or `2K`. H3 Max supports 5–15 whole seconds at `480P` or `768P`, with text or frame images. H3 supports reference images, video and audio; references cannot be mixed with first/last frames. Both models produce one video per request and do not support V1 prompt optimization options. Use canonical `aspect_ratio`; frame inputs determine their own ratio. Reference-video reservations cover the provider's 15-second input limit, with actual usage settled on completion. See the [MiniMax V2 contract](https://platform.minimax.io/docs/api-reference/video-generation-v2-create).

## Batch providers

Batch requests also accept `provider_options`: OpenAI supports `output_expires_after`, and Mistral supports `metadata`. Use canonical provider IDs and do not duplicate these fields at the top level. For example, `provider_options: { "openai": { "output_expires_after": { "anchor": "created_at", "seconds": 86400 } } }` sets OpenAI output retention. Row inputs, models, endpoints, and webhook destinations cannot be overridden through options.

Mistral already has a native batch adapter. Anthropic message batches are polled; other providers may combine polling with native completion notifications. Availability depends on the provider's supported endpoints and the deployment's batch allowlist. Check the batch capability response before submitting a file or inline requests.

Vertex Gemini batches accept inline `requests` with `/v1/generateContent`, or `model` and `prompts`. Select `provider: "google-vertex"` to use Vertex. Successful rows are charged at Batch rates. This adapter requires managed credentials; BYOK, uploaded Files, embeddings and `google-vertex-eu` batches are unavailable. Input is limited to 20 MB and 10,000 requests. Stored input and output expire after 30 days.

Vertex results use `custom_id` to identify each submitted row, with a successful generation in `response.body` or a per-request `error`. Output order can differ from input order. A submission with an uncertain provider outcome remains under manual review with its credit hold retained; avoid creating a replacement until its outcome is confirmed.

Batch completion can include failed rows. Inspect each result using its custom ID instead of assuming that every row succeeded. Keep the original input and job ID until results and billing are reconciled. An uncertain submission must be investigated before resubmitting, because a provider may have accepted the original request.

### Download batch results

After a supported batch reaches a terminal state, its `results_url` points to an authenticated Phaseo download. Use your normal Phaseo API key from the workspace that owns the batch:

```bash theme={null}
curl --fail "https://api.phaseo.app/v1/batches/$BATCH_ID/results" \
  -H "Authorization: Bearer $PHASEO_API_KEY" \
  --output results.jsonl
```

The response streams JSONL through the same endpoint for every supported batch provider. Phaseo combines separate success and error files, converts inline result arrays into JSONL, and follows result pagination. Generated content and per-request errors are preserved. Row fields remain provider-native: use `custom_id` for OpenAI-compatible and Anthropic rows, request metadata for Gemini, and `batch_request_id` for xAI. Anthropic successful rows contain the generated message in `result.message`.

Downloads support OpenAI, Anthropic, Google AI Studio, Mistral, Together, Groq, Alibaba Cloud, Moonshot, Parasail, OVHcloud, and xAI adapters. Provider availability still depends on preview access and the submission allowlist; download support does not enable additional routes. Existing `output_file_id`, `error_file_id`, and file-content endpoints remain available. The batch request-row endpoint contains tracking and billing metadata, not generated message bodies.

Downloading results does not submit another batch or add an inference charge. You do not need provider credentials. Webhooks signal job updates; download the results separately. A terminal job can have partial results or no output at all: the endpoint returns `409` while processing and `404` when no output is available. Save results before the provider's retention period ends. If a download is interrupted, discard the partial file and retry the download, not the batch submission. Inline JSON results are streamed with an 8 MiB per-row safety limit; native JSONL files are streamed without that row limit.

For large outputs, TypeScript's `client.batches.streamResults(batchId, { signal })` returns a `ReadableStream<Uint8Array>` without buffering. Pipe it to your destination and cancel the stream or abort the signal to stop early; there is no fixed total download timeout. Python's `client.batches.stream_results(batch_id)` yields byte chunks with the configured HTTP timeout; close the iterator when stopping early. The generated `retrieveBatchResults` operations return the complete JSONL text and are best suited to small outputs.

### Batch download limits

Batch result downloads allow 10 attempts per workspace per batch in a rolling 30-minute window, shared across API keys and the `/batches` and `/batch` aliases. Attempts that reach download admission count even if the upstream download fails or is cancelled. Ownership and readiness failures do not count. A `429` response includes `Retry-After` in seconds. If the limiter is unavailable, downloads return `503` with `Retry-After: 30`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.