Remix Camera API

Upgrade your chatbot's image generation

Create a consistent visual character from one photo, match proven prompt templates to natural chat requests, and return images that feel made for the conversation.

How it works

From one photo to a better chatbot selfie

Your bot sends the request it already understands. Remix handles character identity, prompt-template retrieval, prompt composition, and image-model routing.

1

Create a character

Upload one photo to start now. Add 10 or more later when you want stronger identity consistency.

2

Send a natural request

Pass the chatbot request and optional recent messages, such as “send a playful mirror selfie.”

3

Get a better image

Remix matches a proven prompt template, adapts it to the character, and runs the right image model.

Example flow

Your user asks: “Send me a selfie before you go out.”

One image request

Character

Maya starts from one photo

A quick safety check is the only gate. Optional custom LoRA training is available for improved consistency.

Chat request

“Send me a selfie before you go out”

Include recent messages when the image should feel like a natural continuation of the conversation.

Remix result

Matched: Casual mirror selfie

A proven template is adapted to Maya instead of sending a generic one-line prompt to an image model.

One photo is enough to start. Training is an optional consistency upgrade after you add 10 or more photos.

Browse the API

Reference

Build with three capabilities

Characters establish identity. Proven Templates turn requests into better prompts. Images return the result.

Base: /api/v1/designBearer authShared credits
CharactersStart from one photo; optionally train with 10+ for stronger consistency.
GET/api/v1/design/charactersList your characters

Return the visual characters this API key can use, including safety-check readiness and eligibility for optional training.

Authentication

API key, opaque design session, or Firebase ID token

GETJavaScript / Node.jsJavaScript/api/v1/design/characters
const response = await fetch("https://remix.camera/api/v1/design/characters", {
  headers: {
    "Authorization": "Bearer <api-key>"
  }
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "characters": [
    {
      "id": "character_maya",
      "name": "Maya",
      "photoCount": 1,
      "status": "ready",
      "readyForGeneration": true,
      "training": {
        "status": "untrained",
        "eligible": false,
        "minimumPhotos": 10,
        "photoCount": 1
      }
    }
  ]
}
POST/api/v1/design/charactersCreate a character

Upload one photo to create a reference character without training. It becomes usable after the required safety check. Add more photos and start optional training as separate, explicit operations.

Authentication

API key, opaque design session, or Firebase ID token

POSTJavaScript / Node.jsJavaScript/api/v1/design/characters
import { openAsBlob } from "node:fs";

const formData = new FormData();
formData.append("name", "Maya");
formData.append("subjectType", "person");
formData.append("photo", await openAsBlob("maya.jpg"), "maya.jpg");

const response = await fetch("https://remix.camera/api/v1/design/characters", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <api-key>"
  },
  body: formData
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "character": {
    "id": "character_maya",
    "name": "Maya",
    "photoCount": 1,
    "status": "processing",
    "readyForGeneration": false,
    "moderation": {
      "status": "processing",
      "reason": null
    },
    "training": {
      "status": "untrained",
      "eligible": false,
      "minimumPhotos": 10,
      "photoCount": 1
    }
  }
}
GET/api/v1/design/characters/{characterId}Check character readiness

Return one owned character with generation readiness, moderation state, photo count, and optional training eligibility.

Authentication

API key, opaque design session, or Firebase ID token

GETJavaScript / Node.jsJavaScript/api/v1/design/characters/{characterId}
const response = await fetch("https://remix.camera/api/v1/design/characters/character_maya", {
  headers: {
    "Authorization": "Bearer <api-key>"
  }
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "character": {
    "id": "character_maya",
    "name": "Maya",
    "status": "ready",
    "readyForGeneration": true,
    "photoCount": 1
  }
}
POST/api/v1/design/characters/{characterId}/photosAdd character photos

Add reference photos in batches under 4 MB to reach the 10-photo threshold for optional training. Adding photos never starts training by itself.

Authentication

API key, opaque design session, or Firebase ID token

POSTJavaScript / Node.jsJavaScript/api/v1/design/characters/{characterId}/photos
import { openAsBlob } from "node:fs";

const formData = new FormData();
formData.append("photo", await openAsBlob("maya-02.jpg"), "maya-02.jpg");
formData.append("photo", await openAsBlob("maya-03.jpg"), "maya-03.jpg");

const response = await fetch("https://remix.camera/api/v1/design/characters/character_maya/photos", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <api-key>"
  },
  body: formData
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "character": {
    "id": "character_maya",
    "photoCount": 3,
    "status": "processing",
    "readyForGeneration": false,
    "moderation": {
      "status": "processing",
      "reason": null
    }
  }
}
POST/api/v1/design/characters/{characterId}/trainingStart optional training

Explicitly start consistency training after the character has at least 10 photos. The normal one-photo flow does not call this operation.

Authentication

API key, opaque design session, or Firebase ID token

POSTJavaScript / Node.jsJavaScript/api/v1/design/characters/{characterId}/training
const response = await fetch("https://remix.camera/api/v1/design/characters/character_maya/training", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <api-key>",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "idempotencyKey": "train-character-maya-v1"
  })
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "training": {
    "started": true,
    "status": "training",
    "requestId": "training_123",
    "inProgress": true
  }
}
Proven TemplatesFind strong, reusable image directions instead of starting from a generic prompt.
GET/api/v1/design/templates/{templateId}Get template detail

Return the proven prompts, preview images, use cases, and recommended model settings for one template.

Authentication

API key, opaque design session, or Firebase ID token

GETJavaScript / Node.jsJavaScript/api/v1/design/templates/{templateId}
const response = await fetch("https://remix.camera/api/v1/design/templates/template_123", {
  headers: {
    "Authorization": "Bearer <api-key>"
  }
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "template": {
    "id": "template_123",
    "title": "Casual mirror selfie",
    "previewImageUrl": "https://...",
    "prompts": [
      {
        "index": 0,
        "prompt": "A natural phone mirror selfie...",
        "recommendedModelId": "nano-banana"
      }
    ]
  }
}
POST/api/v1/design/prompts/composeCompose a chatbot-ready prompt

Adapt a natural request, recent chat, and optional proven template into one character-aware production prompt without generating an image yet.

Authentication

API key, opaque design session, or Firebase ID token

POSTJavaScript / Node.jsJavaScript/api/v1/design/prompts/compose
const response = await fetch("https://remix.camera/api/v1/design/prompts/compose", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <api-key>",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "characterId": "character_maya",
    "request": "Send a playful mirror selfie before going out",
    "templateId": "template_123",
    "recentMessages": [
      {
        "role": "user",
        "content": "Are you ready yet?"
      },
      {
        "role": "assistant",
        "content": "Almost. Deciding if this outfit is too much."
      }
    ],
    "modelId": "auto"
  })
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "request": "Send a playful mirror selfie before going out",
  "composedPrompt": "A realistic candid phone mirror selfie of Maya...",
  "template": {
    "id": "template_123",
    "title": "Casual mirror selfie"
  },
  "modelRecommendation": {
    "requestedModelId": "auto",
    "recommendedModelId": "nano-banana"
  }
}
ImagesSend one chatbot image request; Remix handles templates, character identity, and routing.
POST/api/v1/design/imagesCreate a contextual character image

The plug-and-play chatbot operation. Send a character, natural request, and optional recent messages. Remix retrieves a proven template when available and falls back cleanly to the request itself.

Authentication

API key, opaque design session, or Firebase ID token

POSTJavaScript / Node.jsJavaScript/api/v1/design/images
const response = await fetch("https://remix.camera/api/v1/design/images", {
  method: "POST",
  headers: {
    "Authorization": "Bearer <api-key>",
    "Idempotency-Key": "chatbot-message-123",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "characterId": "character_maya",
    "request": "Send a playful mirror selfie before going out",
    "recentMessages": [
      {
        "role": "user",
        "content": "Are you ready yet?"
      },
      {
        "role": "assistant",
        "content": "Almost. Deciding if this outfit is too much."
      }
    ],
    "modelId": "auto"
  })
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "image": {
    "id": "image_123",
    "status": "queued",
    "statusUrl": "/api/v1/design/images/image_123",
    "requestedModelId": "auto",
    "resolvedModelId": "nano-banana",
    "creditCost": 1,
    "imageUrl": null,
    "template": {
      "id": "template_123",
      "title": "Casual mirror selfie"
    }
  }
}
GET/api/v1/design/images/{imageId}Get image status

Poll the statusUrl returned by image creation until the status is complete and imageUrl is available.

Authentication

API key, opaque design session, or Firebase ID token

GETJavaScript / Node.jsJavaScript/api/v1/design/images/{imageId}
const response = await fetch("https://remix.camera/api/v1/design/images/image_123", {
  headers: {
    "Authorization": "Bearer <api-key>"
  }
});

const data = await response.json();
Example responseJSON
{
  "ok": true,
  "image": {
    "id": "image_123",
    "status": "completed",
    "statusUrl": "/api/v1/design/images/image_123",
    "requestedModelId": "nano-banana",
    "resolvedModelId": "nano-banana",
    "imageUrl": "https://..."
  }
}

Guides

Integration details when you need them

Authentication

Authentication

Use a user-owned API key for normal chatbot, backend, and automation integrations.

Create a key

Sign in at API Keys, give the key a descriptive label, and copy it when it is shown.

ExampleHTTP
Authorization: Bearer rc_live_<id>.<secret>

API keys:

  • act as the owning Remix Camera account
  • use the same characters, credits, and plan limits as that account
  • can be revoked from the API Keys page
  • are stored hashed by Remix Camera

The full key is shown only once.

Keep the key on your server

An rc_live_... key is a server secret.

Do not place it in:

  • browser JavaScript
  • a mobile application bundle
  • a public repository
  • a chatbot character card
  • a client-side plugin setting visible to other users

Store it in an environment variable or secret manager:

ExampleShell
export REMIX_API_KEY="rc_live_..."
ExampleJavaScript
const response = await fetch("https://remix.camera/api/v1/design/characters", {
  headers: {
    Authorization: `Bearer ${process.env.REMIX_API_KEY}`,
  },
});

Test the key

GET /characters is the recommended harmless authentication check because it requires a valid credential and does not spend image credits.

ExampleShell
curl https://remix.camera/api/v1/design/characters \
  -H "Authorization: Bearer $REMIX_API_KEY"

Do not use GET /models as an authentication test. Model discovery is public-readable and can succeed when a bearer token is missing or invalid.

Browser applications

First-party browser applications already signed into Remix Camera may use a Firebase ID token:

ExampleHTTP
Authorization: Bearer <firebase-id-token>

Do not ask external users to copy Firebase tokens. Use API keys or the supported device-pairing integration instead.

Local clients and device pairing

Supported desktop and local-client integrations can use an opaque user-bound design session:

ExampleHTTP
Authorization: Bearer dapi_<id>.<secret>

These sessions are:

  • opaque and hashed before storage
  • revocable
  • limited per user
  • intended for device-pairing flows such as the Remix Camera SillyTavern setup command

The device start, approve, poll, session exchange, session listing, and session revoke routes are integration infrastructure. They remain available for current clients but are intentionally not part of the primary chatbot-image API reference.

Key management API compatibility

The existing /api/v1/design/auth/api-keys* routes remain available for Remix Camera's signed-in account UI. They require an interactive Firebase ID token; an API key cannot create or revoke other API keys.

Normal developers should create, inspect, and revoke keys through API Keys.

Errors, Billing, and Limits

Errors, Billing, and Limits

Error shape

Primary Character, Template, Prompt, and Image endpoints return:

ExampleJSON
{
  "ok": false,
  "error": {
    "code": "invalid_request",
    "message": "characterId is required",
    "retryable": false
  }
}

When available, error.details contains structured context such as the required photo count or current subscription state.

Error codes

  • unauthorized — the bearer token is missing, invalid, expired, or revoked
  • forbidden — the account cannot use the requested resource or capability
  • invalid_request — required fields are missing or an unsupported combination was sent
  • not_found — the owned character, template, or image job could not be found
  • profile_not_ready — the selected character cannot yet use the requested model
  • idempotency_conflict — the key was already used for different request fields
  • idempotency_in_progress — the original keyed request is active; retry the identical request with the same key after Retry-After
  • idempotency_indeterminate — the original request may have reached the provider; do not submit a replacement request automatically
  • insufficient_credits — the account does not have enough image credits
  • moderated_prompt — the image request was blocked by prompt moderation
  • moderated_profile — the character is blocked or awaiting required age review
  • rate_limited — retry only after the Retry-After duration
  • provider_unavailable — an image provider is temporarily unavailable
  • internal_error — an unexpected server-side failure

Retry guidance

Retry only when:

  • retryable is true
  • the code is rate_limited and the Retry-After delay has elapsed
  • the code is provider_unavailable

Do not automatically retry validation, authentication, moderation, or insufficient-credit failures.

Training accepts idempotencyKey; reuse it when retrying the same training action.

For POST /images, send one stable Idempotency-Key header per logical image request. On a transport timeout or idempotency_in_progress, retry the identical body with the same key after Retry-After. A completed retry replays the original response and does not spend another image credit. Never reuse a key for different request fields or automatically replace an idempotency_indeterminate request with a new key. When a response includes statusUrl, poll that URL instead of submitting the image again.

Character photo rules

  • creating a character requires at least one supported image
  • one photo creates a reference character that can be used immediately when moderation is clear
  • training requires at least 10 photos
  • adding photos does not automatically start training
  • training must be requested explicitly
  • character create/photo batches are capped at 4 MB per request
  • character photo uploads remain subject to the current file-type, file-size, moderation, and maximum-photo limits

If train=true is sent to character creation, the request returns invalid_request. Add photos first, wait for safety checks to clear, then call the dedicated training operation.

Image inputs

POST /images accepts JSON and creates exactly one image. It currently rejects local and remote reference-image inputs until source media can pass an affirmative strict age-safety clearance before generation.

Billing and credits

API keys and opaque design sessions are user-bound. API usage draws from the same credits and plan limits as the Remix Camera web application.

Credit-spending operations include:

  • image generation and remix
  • optional character training

Template search, template detail, prompt composition, character listing, character status, and image-status polling do not spend image-generation credits. Prompt composition may still be subject to service rate limits.

There is not currently a separate API-only billing balance.

Model selection

Use modelId: "auto" unless your integration needs a specific supported model. Image responses distinguish the requested and resolved model:

ExampleJSON
{
  "requestedModelId": "auto",
  "resolvedModelId": "nano-banana"
}

Compatibility routes

Older /profiles, /packs, /generations, /remix-from-image, and integration-auth routes remain available. Some preserve legacy error bodies for existing clients. New integrations should use the primary Character, Template, Prompt, and Image endpoints for the normalized error contract above.

Chatbot Image Quickstart

Chatbot Image Quickstart

This guide adds consistent, contextual images to an existing chatbot.

The complete flow is:

  1. create a visual character from one photo
  2. poll the character until its required safety check is complete
  3. send the same natural image request your chatbot already understands, then poll its status URL

Remix Camera handles prompt-template retrieval, character identity, prompt adaptation, and image-model routing.

Before you start

Create an API key at API Keys and store it only on your server.

ExampleShell
export REMIX_API_KEY="rc_live_..."

API requests use:

ExampleHTTP
Authorization: Bearer <api-key>

1. Create a character from one photo

One photo creates a reference character without training. It becomes usable after the required safety check.

ExampleShell
curl -X POST https://remix.camera/api/v1/design/characters \
  -H "Authorization: Bearer $REMIX_API_KEY" \
  -F "name=Maya" \
  -F "subjectType=person" \
  -F "[email protected]"

The response includes the character id needed for image requests:

ExampleJSON
{
  "ok": true,
  "character": {
    "id": "character_maya",
    "name": "Maya",
    "photoCount": 1,
    "status": "processing",
    "readyForGeneration": false,
    "moderation": {
      "status": "processing",
      "reason": null
    },
    "training": {
      "status": "untrained",
      "eligible": false,
      "minimumPhotos": 10,
      "photoCount": 1
    }
  }
}

For a person character, the upload returns immediately while the required safety check runs. Poll the character before generating:

ExampleShell
curl https://remix.camera/api/v1/design/characters/character_maya \
  -H "Authorization: Bearer $REMIX_API_KEY"

Continue when readyForGeneration is true. A blocked moderation state requires review and must not be retried as generation.

2. Ask for an image naturally

Send the request and, when helpful, the recent conversation. You do not need to search templates or write an image-model prompt first.

ExampleShell
curl -X POST https://remix.camera/api/v1/design/images \
  -H "Authorization: Bearer $REMIX_API_KEY" \
  -H "Idempotency-Key: chatbot-message-123" \
  -H "Content-Type: application/json" \
  -d '{
    "characterId": "character_maya",
    "request": "Send a playful mirror selfie before going out",
    "recentMessages": [
      { "role": "user", "content": "Are you ready yet?" },
      { "role": "assistant", "content": "Almost. Deciding if this outfit is too much." }
    ],
    "modelId": "auto"
  }'

The image operation returns immediately with a status URL:

ExampleJSON
{
  "ok": true,
  "image": {
    "id": "image_123",
    "status": "queued",
    "statusUrl": "/api/v1/design/images/image_123",
    "requestedModelId": "auto",
    "resolvedModelId": "nano-banana",
    "creditCost": 1,
    "imageUrl": null,
    "template": {
      "id": "template_123",
      "title": "Casual mirror selfie"
    }
  }
}

When a proven template matches the request, the response identifies it. When none matches, Remix Camera falls back to the natural request instead of blocking the image.

Use one stable Idempotency-Key for each logical image request. If the connection times out, retry the identical request with the same key. Never reuse that key for different request fields.

3. Poll the image

Use the returned statusUrl:

ExampleShell
curl https://remix.camera/api/v1/design/images/image_123 \
  -H "Authorization: Bearer $REMIX_API_KEY"

Stop polling when status is completed or a terminal error state is returned.

ExampleJSON
{
  "ok": true,
  "image": {
    "id": "image_123",
    "status": "completed",
    "statusUrl": "/api/v1/design/images/image_123",
    "resolvedModelId": "nano-banana",
    "imageUrl": "https://..."
  }
}

Optional: inspect the prompt library

Your chatbot can search the same proven template library directly:

ExampleShell
curl "https://remix.camera/api/v1/design/templates?query=send%20a%20playful%20mirror%20selfie&pageSize=6" \
  -H "Authorization: Bearer $REMIX_API_KEY"

Use this when you want to show template choices, previews, or matching explanations before generation. It is not required for the one-call /images flow.

Optional: compose without generating

Use prompt composition when your application wants to review or edit the final prompt before spending image credits:

ExampleShell
curl -X POST https://remix.camera/api/v1/design/prompts/compose \
  -H "Authorization: Bearer $REMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "characterId": "character_maya",
    "request": "Send a playful mirror selfie before going out",
    "templateId": "template_123",
    "modelId": "auto"
  }'

Prompt composition can use the existing enhancement service, so call it only when the composed prompt is itself useful to your application. The normal /images operation does not add this extra prompt-composition call.

Optional: train for stronger consistency

Add photos until the character has at least 10. Keep each request under 4 MB and repeat the call in small batches when needed:

ExampleShell
curl -X POST https://remix.camera/api/v1/design/characters/character_maya/photos \
  -H "Authorization: Bearer $REMIX_API_KEY" \
  -F "[email protected]" \
  -F "[email protected]"

Adding photos does not start training. Start it explicitly when ready:

ExampleShell
curl -X POST https://remix.camera/api/v1/design/characters/character_maya/training \
  -H "Authorization: Bearer $REMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "idempotencyKey": "train-character-maya-v1"
  }'

Training uses the account's existing Remix Camera training entitlement. Reuse the same idempotency key when retrying the same training action.

Recommended chatbot behavior

Treat the request as the image behavior the character is performing, not a low-level model prompt.

Good requests include:

  • Send a casual morning selfie from the kitchen
  • Show what you would wear on this date
  • Send a reaction image that fits the last message
  • Recreate this vacation photo with my character

Include recent messages only when they provide useful scene, outfit, mood, or relationship context. Do not send an entire private conversation when a few relevant messages are enough.