Adobe Firefly API
"Adobe Firefly: text-to-image generation, generative fill, generative expand, style reference, content credentials, REST API"
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 linesAdobe 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
contentClassto 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
negativePromptfield 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
Related Skills
Cloudinary Image Generation & Manipulation
"Cloudinary: image and video upload, transformation, AI-based generation, background removal, CDN delivery, URL-based API"
DALL-E Image Generation
"DALL-E API (OpenAI): image generation, editing, variations, quality/style params, size options, Node SDK"
fal.ai Image Generation
"fal.ai: fast inference, Flux, realtime image gen, queue API, webhooks, JavaScript SDK, serverless GPU"
Imgix Image Processing
"Imgix: real-time image processing and CDN, URL-based transformations, resizing, cropping, watermarking, face detection, format optimization"
Leonardo AI Image Generation
"Leonardo AI: image generation API, fine-tuned models, canvas editing, texture generation, REST API"
Replicate Image Generation
Replicate for image generation: Flux, SDXL, img2img, inpainting, upscaling, predictions API, webhooks, streaming