# How to Use Next.js App Router API Routes for OpenMAIC Media Generation

> Learn to use Next.js App Router API routes for OpenMAIC media generation. Access video, image, and TTS features via POST requests and receive typed responses.

- Repository: [MAIC/OpenMAIC](https://github.com/THU-MAIC/OpenMAIC)
- Tags: how-to-guide
- Published: 2026-09-01

---

**OpenMAIC exposes video, image, and text-to-speech generation capabilities through standard Next.js App Router API routes in `app/api/generate/*/route.ts`, accepting POST requests with JSON payloads and returning uniform typed responses via `apiSuccess` and `apiError` helpers.**

OpenMAIC implements its entire backend within the Next.js 13+ App Router architecture, leveraging serverless API route handlers to process media generation requests. Each endpoint follows a consistent six-step pipeline defined in feature-specific [`route.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/route.ts) files under the `app/api/generate/` directory, enabling seamless integration from frontend clients or external HTTP services. This guide covers the complete request lifecycle, provider resolution logic, and implementation details based on the THU-MAIC/OpenMAIC source code.

## Core Route Architecture

Every OpenMAIC API route follows an identical architectural pattern implemented in `app/api/generate/[feature]/route.ts` files. The system processes requests through a standardized pipeline that ensures type safety, provider abstraction, and unified usage analytics.

### Route Structure and Entry Points

Each media type exposes a dedicated endpoint that exports a `maxDuration` constant specifying the serverless timeout:

- **Video generation**: [`app/api/generate/video/route.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/app/api/generate/video/route.ts) exports `maxDuration = 300` (5 minutes)
- **Image generation**: [`app/api/generate/image/route.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/app/api/generate/image/route.ts) exports `maxDuration = 300` (5 minutes)  
- **Text-to-speech**: [`app/api/generate/tts/route.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/app/api/generate/tts/route.ts) exports `maxDuration = 30` (30 seconds)

These duration values enforce hard limits on provider response times and inform frontend polling logic.

### Request Processing Pipeline

Every incoming request flows through six distinct layers before returning a response:

1. **Request Reception**: The handler receives a standard `NextRequest` object containing the JSON body and optional headers.
2. **Validation**: The system validates required fields (e.g., `prompt` for video/image, `text` for TTS) and extracts optional provider-selection headers.
3. **Provider Resolution**: Using [`lib/server/provider-config.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/provider-config.ts), the route resolves the concrete provider ID, API key, base URL, and model ID via `resolveServerVideoProviderId`, `resolveVideoApiKey`, and `resolveVideoModel` (or equivalent for other media types).
4. **Media Generation**: The route calls the specific generation function (`generateVideo`, `generateImage`, or `generateTTS`) from the respective provider implementation files in `lib/media/` or `lib/audio/`.
5. **Usage Recording**: The system persists generation metrics via `recordGenerationUsage` in [`lib/server/usage-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/usage-storage.ts) for analytics tracking.
6. **Response Formatting**: The route returns a uniform JSON envelope using `apiSuccess` or `apiError` helpers from [`lib/server/api-response.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/api-response.ts).

## Calling the API from Client Applications

OpenMAIC routes accept standard HTTP POST requests with JSON payloads. Since the API runs under the same domain as the Next.js application, you use relative paths starting with `/api/`.

### Base Client Implementation Pattern

Wrap your fetch calls in a reusable helper that handles the uniform response format:

```typescript
async function callOpenMaicApi<T>(
  path: string, 
  payload: unknown, 
  extraHeaders?: Record<string, string>
): Promise<T> {
  const resp = await fetch(path, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      ...extraHeaders,
    },
    body: JSON.stringify(payload),
  });

  const data = await resp.json();
  
  if (!data.success) {
    throw new Error(`${data.errorCode}: ${data.error}`);
  }
  
  return data as T;
}

```

This helper enforces type safety and automatically throws on API errors using the `errorCode` and `error` fields from the standardized response envelope.

### Video Generation Endpoint

The video generation route in [`app/api/generate/video/route.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/app/api/generate/video/route.ts) accepts prompts with optional duration, aspect ratio, and resolution parameters:

```typescript
const videoResult = await callOpenMaicApi<{
  result: {
    url: string;
    width: number;
    height: number;
    duration: number;
  };
}>('/api/generate/video', {
  prompt: 'A futuristic classroom with holographic screens',
  duration: 30,          // optional, in seconds
  aspectRatio: '16:9',   // optional
  resolution: '1080p',   // optional
}, {
  // Optional headers to override default provider configuration
  'x-video-provider': 'openai-video',
  'x-video-model': 'gpt-4o-mini',
});

console.log('Video URL:', videoResult.result.url);

```

The handler resolves the specific video provider using `resolveServerVideoProviderId`, `resolveVideoApiKey`, and `resolveVideoModel` from [`lib/server/provider-config.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/provider-config.ts) before invoking `generateVideo` from [`lib/media/video-providers.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/media/video-providers.ts).

### Image Generation Endpoint

The image route in [`app/api/generate/image/route.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/app/api/generate/image/route.ts) supports dimension specifications via explicit width/height or aspect ratio mapping:

```typescript
const imageResult = await callOpenMaicApi<{
  result: {
    url: string;
    width: number;
    height: number;
  };
}>('/api/generate/image', {
  prompt: 'A cute robot teaching math to children',
  aspectRatio: '1:1', // Automatically maps to 1024×1024 via aspectRatioToDimensions()
}, {
  'x-image-provider': 'stabilityai',
  'x-image-model': 'sdxl-v2',
});

console.log('Image URL:', imageResult.result.url);

```

The route supports optional `negativePrompt`, `width`, `height`, and `style` parameters. Provider resolution follows the same pattern as video generation, utilizing [`lib/media/image-providers.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/media/image-providers.ts) and the shared configuration helpers.

### Text-to-Speech Generation Endpoint

The TTS route in [`app/api/generate/tts/route.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/app/api/generate/tts/route.ts) returns base64-encoded audio payloads:

```typescript
const ttsResult = await callOpenMaicApi<{
  audioId: string;
  base64: string;   // Base64-encoded audio data
  format: string;   // e.g., 'mp3'
}>('/api/generate/tts', {
  text: 'Welcome to the AI classroom!',
  audioId: 'welcome-001',
  ttsProviderId: 'openai-tts',
  ttsModelId: 'gpt-4o-mini',
  ttsVoice: 'alloy',
  ttsSpeed: 1.0,    // optional
}, {
  // Provide API key only if not using a managed provider
  'x-api-key': 'sk-YOUR_OPENAI_KEY',
});

// Convert base64 to Uint8Array for audio playback
const audioBlob = Uint8Array.from(
  atob(ttsResult.base64), 
  c => c.charCodeAt(0)
);

```

The TTS implementation in [`lib/audio/tts-providers.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/audio/tts-providers.ts) handles the concrete generation while the route manages provider resolution via the shared configuration system.

## Provider Configuration and Request Headers

OpenMAIC uses a flexible provider resolution system that supports managed providers (pre-configured server-side) and per-request overrides via HTTP headers.

### Available Configuration Headers

- **`x-video-provider`** / **`x-image-provider`**: Override the default provider for the specific media type (e.g., `openai-video`, `runwayml-video`, `stabilityai`).
- **`x-video-model`** / **`x-image-model`** / **`x-tts-model`**: Specify the exact model ID for the selected provider.
- **`x-api-key`**: Supply a per-request API key, used only when not utilizing a managed provider configuration.
- **`x-base-url`**: Override the provider's base URL for self-hosted instances (subject to SSRF protection guards in [`lib/server/provider-config.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/provider-config.ts)).

If you omit these headers, the system falls back to the first configured provider for that media type using the `resolveServer*ProviderId` helpers.

### Managed vs. Unmanaged Providers

**Managed providers** have API keys and base URLs pre-configured in the server environment variables. For these, you omit the `x-api-key` header entirely. **Unmanaged providers** require you to pass the `x-api-key` header with each request, allowing client-side key rotation without server redeployment.

## Error Handling and Response Format

All OpenMAIC API routes return a uniform JSON envelope regardless of success or failure:

```json
{
  "success": false,
  "errorCode": "MISSING_REQUIRED_FIELD",
  "error": "Missing prompt"
}

```

### Response Structure

- **`success`**: Boolean indicating request status.
- **`result`**: Present only when `success` is true; contains the generated media data.
- **`errorCode`**: Machine-readable error identifier from `API_ERROR_CODES` defined in [`lib/server/api-response.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/api-response.ts).
- **`error`**: Human-readable description of the failure.

### Common Error Codes

Client applications should inspect `errorCode` to implement specific recovery logic:

- **`MISSING_REQUIRED_FIELD`**: The request body lacks a mandatory parameter (e.g., missing `prompt`).
- **`PROVIDER_RESOLUTION_FAILED`**: The system could not resolve a valid provider from headers or configuration.
- **`GENERATION_FAILED`**: The underlying provider returned an error during media generation.
- **`USAGE_LIMIT_EXCEEDED`**: The request exceeds configured rate limits or quotas recorded in [`lib/server/usage-storage.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/usage-storage.ts).

## Summary

- **Route Location**: All media generation endpoints reside in `app/api/generate/[feature]/route.ts` files within the Next.js App Router structure.
- **Standardized Flow**: Every route implements a six-step pipeline: request reception, validation, provider resolution, media generation, usage recording via `recordGenerationUsage`, and response formatting via `apiSuccess`/`apiError`.
- **Provider Flexibility**: Use headers (`x-video-provider`, `x-image-provider`, `x-api-key`) to override default providers or pass client-specific credentials without redeploying the server.
- **Uniform Responses**: All endpoints return JSON envelopes containing boolean `success` status and either a `result` object or `errorCode`/`error` fields.
- **Type Safety**: Implementation in TypeScript ensures typed request bodies and responses, with concrete provider implementations in [`lib/media/video-providers.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/media/video-providers.ts), [`lib/media/image-providers.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/media/image-providers.ts), and [`lib/audio/tts-providers.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/audio/tts-providers.ts).

## Frequently Asked Questions

### How do I specify a different AI provider for a single request?

Pass the appropriate provider header (`x-video-provider`, `x-image-provider`, or `x-tts-provider`) with your POST request. For example, set `x-video-provider: runwayml-video` to use RunwayML instead of the default OpenAI video model. The server resolves the provider configuration using [`lib/server/provider-config.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/provider-config.ts) and falls back to the first configured server-side provider if headers are omitted.

### What is the maximum duration for API requests, and how is it enforced?

Each route exports a `maxDuration` constant (typically 300 seconds for video/image generation and 30 seconds for TTS). This value defines the serverless function timeout enforced by the hosting platform and is consumed by frontend polling logic to manage user expectations for long-running generations.

### Can I use these API routes from an external application or only from the Next.js frontend?

You can call these routes from any HTTP client. While the examples use relative paths (`/api/generate/video`), external applications should use the full deployment URL. Authentication works via the `x-api-key` header for unmanaged providers, or via pre-configured managed providers that do not require client-side keys.

### How does error handling work when a provider API fails?

The route catches provider-specific errors in the generation step and returns a standardized error envelope with `success: false`, an `errorCode` from the `API_ERROR_CODES` enumeration in [`lib/server/api-response.ts`](https://github.com/THU-MAIC/OpenMAIC/blob/main/lib/server/api-response.ts), and a descriptive `error` message. Client code should verify `data.success` before accessing `data.result`, and implement branch logic based on specific `errorCode` values to handle retries or user notifications appropriately.