Skip to main content
Technology & EngineeringImage Generation Services202 lines

Adobe Firefly API

"Adobe Firefly: text-to-image generation, generative fill, generative expand, style reference, content credentials, REST API"

Quick Summary11 lines
You are an expert in using the Adobe Firefly Services API for commercial-safe image generation, generative fill, and generative expand.

## Key Points

- Always set `contentClass` to either `"photo"` or `"art"` to guide the model toward the right visual style; omitting it may produce inconsistent results.
- Cache access tokens and refresh them before expiry (tokens typically last 24 hours) rather than requesting a new token per API call.
- Use the `negativePrompt` field to exclude unwanted visual elements rather than trying to describe their absence in the main prompt.
- Generated image URLs from the Firefly API are temporary (pre-signed) and expire. Download and store the images immediately rather than saving the URLs for later use.
- The API enforces specific allowed size dimensions (e.g., 2048x2048, 2048x1024); arbitrary sizes will return a 400 error. Check the API documentation for the current list of supported dimensions.
skilldb get image-generation-services-skills/Adobe Firefly APIFull skill: 202 lines
Paste into your CLAUDE.md or agent config

Adobe Firefly — Image Generation API

You are an expert in using the Adobe Firefly Services API for commercial-safe image generation, generative fill, and generative expand.

Core Philosophy

Overview

Adobe Firefly is Adobe's family of generative AI models, accessible via a REST API through Adobe Developer Console. Firefly is specifically designed for commercial safety — it is trained on licensed Adobe Stock content, openly licensed content, and public domain content. The API provides text-to-image generation, generative fill (inpainting), generative expand (outpainting), and style/structure references. All generated images include Content Credentials (C2PA metadata) that indicate AI involvement. Access requires an Adobe Developer Console project with Firefly API credentials.

Setup & Configuration

Obtain an access token using OAuth server-to-server credentials:

interface FireflyConfig {
  clientId: string;
  clientSecret: string;
  baseUrl: string;
}

async function getAccessToken(config: FireflyConfig): Promise<string> {
  const params = new URLSearchParams({
    grant_type: "client_credentials",
    client_id: config.clientId,
    client_secret: config.clientSecret,
    scope: "openid,AdobeID,firefly_api",
  });

  const response = await fetch("https://ims-na1.adobelogin.com/ims/token/v3", {
    method: "POST",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
    body: params.toString(),
  });

  const data = await response.json();
  return data.access_token;
}

const config: FireflyConfig = {
  clientId: process.env.FIREFLY_CLIENT_ID!,
  clientSecret: process.env.FIREFLY_CLIENT_SECRET!,
  baseUrl: "https://firefly-api.adobe.io",
};

Core Patterns

Text-to-image generation

async function generateImage(
  accessToken: string,
  prompt: string,
  options?: {
    n?: number;
    size?: { width: number; height: number };
    contentClass?: "photo" | "art";
    negativePrompt?: string;
  }
) {
  const response = await fetch(`${config.baseUrl}/v3/images/generate`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "x-api-key": config.clientId,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt,
      n: options?.n ?? 1,
      size: options?.size ?? { width: 2048, height: 2048 },
      contentClass: options?.contentClass ?? "photo",
      negativePrompt: options?.negativePrompt,
    }),
  });

  const result = await response.json();
  // result.outputs is an array of { seed, image: { url } }
  return result.outputs;
}

// Usage
const images = await generateImage(token, "A mountain lake at sunrise, photorealistic", {
  n: 4,
  size: { width: 2048, height: 1024 },
  contentClass: "photo",
  negativePrompt: "blurry, low quality",
});

Generative fill (inpainting)

async function generativeFill(
  accessToken: string,
  imageUrl: string,
  maskUrl: string,
  prompt: string
) {
  const response = await fetch(`${config.baseUrl}/v3/images/fill`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "x-api-key": config.clientId,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      image: { source: { url: imageUrl } },
      mask: { source: { url: maskUrl } },
      prompt,
    }),
  });

  return (await response.json()).outputs;
}

Style reference

async function generateWithStyleRef(
  accessToken: string,
  prompt: string,
  styleImageUrl: string
) {
  const response = await fetch(`${config.baseUrl}/v3/images/generate`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "x-api-key": config.clientId,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      prompt,
      n: 1,
      size: { width: 2048, height: 2048 },
      styles: {
        referenceImage: { source: { url: styleImageUrl } },
        strength: 60, // 1-100, how strongly to apply the style
      },
    }),
  });

  return (await response.json()).outputs;
}

Generative expand (outpainting)

async function generativeExpand(
  accessToken: string,
  imageUrl: string,
  targetSize: { width: number; height: number },
  prompt?: string
) {
  const response = await fetch(`${config.baseUrl}/v3/images/expand`, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${accessToken}`,
      "x-api-key": config.clientId,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      image: { source: { url: imageUrl } },
      size: targetSize,
      prompt, // optional context for the expanded area
    }),
  });

  return (await response.json()).outputs;
}

Best Practices

  • Always set contentClass to either "photo" or "art" to guide the model toward the right visual style; omitting it may produce inconsistent results.
  • Cache access tokens and refresh them before expiry (tokens typically last 24 hours) rather than requesting a new token per API call.
  • Use the negativePrompt field to exclude unwanted visual elements rather than trying to describe their absence in the main prompt.

Common Pitfalls

  • Generated image URLs from the Firefly API are temporary (pre-signed) and expire. Download and store the images immediately rather than saving the URLs for later use.
  • The API enforces specific allowed size dimensions (e.g., 2048x2048, 2048x1024); arbitrary sizes will return a 400 error. Check the API documentation for the current list of supported dimensions.

Anti-Patterns

Using the service without understanding its pricing model. Cloud services bill differently — per request, per GB, per seat. Deploying without modeling expected costs leads to surprise invoices.

Hardcoding configuration instead of using environment variables. API keys, endpoints, and feature flags change between environments. Hardcoded values break deployments and leak secrets.

Ignoring the service's rate limits and quotas. Every external API has throughput limits. Failing to implement backoff, queuing, or caching results in dropped requests under load.

Treating the service as always available. External services go down. Without circuit breakers, fallbacks, or graceful degradation, a third-party outage becomes your outage.

Coupling your architecture to a single provider's API. Building directly against provider-specific interfaces makes migration painful. Wrap external services in thin adapter layers.

Install this skill directly: skilldb add image-generation-services-skills

Get CLI access →