Firefly Services Bootstrap
Gets a brand-new Firefly Services project from zero to a verified first API call in one workflow. Designed for the opening 30 minutes of an FDE engagement: console project → workspace → OAuth Server-to-Server credentials → API subscription → environment wiring → token retrieval → smoke-test call.
If the user already has working credentials and just needs to call the API, use firefly-services-auth directly. If credentials exist but auth is failing, use firefly-services-troubleshoot.
When to Use This Skill
Use this skill when:
- The user is starting a new Firefly Services project and has no
client_id/client_secretyet - An FDE engagement is kicking off at a new customer account
- An existing Developer Console project needs Firefly Services added as a new API
- The user mentions "bootstrap", "set up", "from scratch", "new credentials", or "first API call"
Do NOT use this skill when:
- A valid
FIREFLY_SERVICES_ACCESS_TOKENalready exists in the current session - The user is debugging a 401/403/429 — use
firefly-services-troubleshoot - The user is migrating from JWT credentials — JWT reached end-of-life on June 30, 2025 and all certificates expired March 1, 2026, so any remaining JWT integration is already non-functional; rebuild with OAuth Server-to-Server instead
Prerequisites
| Requirement | How to verify |
|---|---|
| Adobe ID with admin access to an IMS org | aio console org list --json returns at least one org |
| The org has a Firefly Services entitlement | aio console api list --json includes a Firefly service code |
aio CLI installed and authenticated |
aio --version returns a version, aio auth ctx --list shows at least one IMS context (log in with aio auth login if empty) |
| Node 18+ for the SDK install step | node --version returns v18.x or higher |
curl for the token round-trip smoke test |
curl --version returns curl 7.x or higher |
If the IMS org does not have a Firefly Services entitlement, stop. The customer needs Adobe to provision it before any code path here will succeed. The product is sold separately from a base Creative Cloud subscription.
Related Skills
firefly-services-auth— Retrieve and refresh OAuth tokens once credentials existfirefly-services-troubleshoot— Decode 401/403/429 responses and IMS scope mismatchesfirefly-services-storage-refs— Wire up thestoragesource/destination layer required by most generate/edit endpointsfirefly-generate-image-v3-async— First real workload after bootstrap
Step 1 — Confirm or create the Developer Console project
List existing projects in the target org so you do not duplicate one:
aio console org select <orgId>
aio console project list --json
If a project for this customer exists, capture its name and continue to Step 2.
If no project exists, create one:
aio console project create \
--name "<customer>-firefly-services" \
--title "<Customer> Firefly Services" \
--description "Firefly Services integration for <Customer>" \
--json
Naming convention: <customer-slug>-firefly-services. Lowercase, hyphenated, no spaces. The slug is what every downstream consumer will see in tokens, dashboards, and audit logs.
Step 2 — Create the workspace
Every Console project needs at least one non-Production workspace. Stage is the convention; use a more descriptive name only when several long-lived workspaces will share the project.
aio console workspace create \
--projectName "<customer>-firefly-services" \
--name Stage \
--title "Stage workspace" \
--json
If the workspace already exists, this fails with a clear "already exists" error. Read existing workspaces with aio console workspace list --projectName <p> --json and continue to Step 3.
Step 3 — Subscribe Firefly Services APIs to the workspace
Discover the exact service code(s) available to this IMS org:
aio console api list --json
Firefly Services is offered as a set of related API products. For a typical FDE engagement subscribe at minimum:
| Service | Why |
|---|---|
FireflyAPI / FireflyServicesSDK (name varies by org) |
Generate / expand / fill image, generate similar, custom models |
PhotoshopAPI |
Smart object replacement, action runner, PSD composition |
LightroomAPI |
Batch image processing, preset application |
ContentTaggingAPI (optional) |
Asset auto-tagging for downstream brand-guardrail workflows |
Subscribe with workspace api add:
aio console workspace api add \
--projectName "<customer>-firefly-services" \
--workspaceName Stage \
--service-code FireflyAPI \
--json
aio console workspace api add \
--projectName "<customer>-firefly-services" \
--workspaceName Stage \
--service-code PhotoshopAPI \
--json
If a service code requires a product profile (the org has multiple Firefly entitlements with different licensing), workspace api add will return product profile required. Resolve with:
aio console workspace api add \
--projectName "<customer>-firefly-services" \
--workspaceName Stage \
--service-code FireflyAPI \
--license-config FireflyAPI=<ProfileName> \
--json
Profile names are org-specific, so get the name from the customer's org admin.
Step 4 — Provision OAuth Server-to-Server credentials
Adobe deprecated JWT credentials on June 30, 2025; all certificates expired March 1, 2026. Use OAuth Server-to-Server exclusively for any new project — even when migrating an existing one. Do not maintain mixed credential types.
Credential creation is a Developer Console UI step — the aio console plugin manages projects, workspaces, and API subscriptions, but has no credential-creation command. Deep-link straight to the selected project/workspace:
aio console open
In the Console UI, open the Stage workspace and add the credential: Add API (if prompted for a credential type when adding the first API) or Credentials → Add Credential, then choose OAuth Server-to-Server and name it <customer>-firefly-sts.
The credential screen presents the client_id and client_secret. Capture both immediately. The secret is not retrievable later — only rotatable. Store them in the customer's secrets manager (AWS Secrets Manager, Azure Key Vault, etc.), never in source control.
Step 5 — Wire the local environment
Export both credentials so subsequent commands can pick them up:
export FIREFLY_SERVICES_CLIENT_ID=<client_id>
export FIREFLY_SERVICES_CLIENT_SECRET=<client_secret>
For long-lived shells, persist to a .env.local (gitignored) and load with direnv or a project-level loader. Do not commit .env* files. Standard .gitignore patterns must include .env, .env.*, and *.secret.
Step 6 — Retrieve the first access token
The token round-trip is the canonical smoke test for credentials. If this works, the project is correctly provisioned.
curl --location 'https://ims-na1.adobelogin.com/ims/token/v3' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=client_credentials' \
--data-urlencode "client_id=$FIREFLY_SERVICES_CLIENT_ID" \
--data-urlencode "client_secret=$FIREFLY_SERVICES_CLIENT_SECRET" \
--data-urlencode 'scope=openid,AdobeID,session,additional_info,read_organizations,firefly_api,ff_apis,firefly_enterprise,creative_sdk'
The first seven scopes are enough for the generate-image smoke test alone; firefly_enterprise and creative_sdk cover the Custom Models and Photoshop/Lightroom workloads Step 3 subscribes, so request the full set from the start.
A successful response:
{"access_token": "eyJhbGc...", "token_type": "bearer", "expires_in": 86399}
Tokens are valid for ~24 hours. Production code must refresh proactively before expiry — see firefly-services-auth for the refresh pattern.
Export the token:
export FIREFLY_SERVICES_ACCESS_TOKEN=<access_token>
If the curl call returns invalid_client, the client_secret is wrong. If it returns unauthorized_client, the workspace is not subscribed to the Firefly Services API (Step 3 was skipped or incomplete). Note that IMS ignores unrecognized scope names rather than rejecting them (verified against the live endpoint), so a misspelled scope still yields a token that looks fine but lacks the intended entitlement and fails later at the API with 401/403. Request the full scope set, and remember firefly_api and ff_apis are both required even though they look redundant.
Step 7 — Install the SDK and run the smoke-test call
For Node.js / TypeScript projects:
npm install @adobe/firefly-apis @adobe/firefly-services-common-apis
For Photoshop / Lightroom workflows add the relevant SDKs:
npm install @adobe/photoshop-apis @adobe/lightroom-apis
As of this writing, Adobe publishes JavaScript SDKs — check developer.adobe.com for current language support. Python projects call the REST endpoints with requests plus their own typed wrappers.
Smoke-test the credentials with a minimal generate-image call:
curl -X POST 'https://firefly-api.adobe.io/v3/images/generate' \
-H "Authorization: Bearer $FIREFLY_SERVICES_ACCESS_TOKEN" \
-H "X-Api-Key: $FIREFLY_SERVICES_CLIENT_ID" \
-H 'Content-Type: application/json' \
--data-raw '{"prompt":"a single red apple on a white background","numVariations":1,"size":{"width":1024,"height":1024}}'
A successful response includes an outputs[0].image.url field. Open the URL in a browser to confirm the actual image was generated. If the presigned URL loads but the image is blank, retry once before debugging further — transient issues occasionally resolve on retry.
If you get a 403 with Forbidden and no detail, the most likely cause is that the workspace is subscribed but the credentials have not yet propagated. Newly issued credentials can take a few minutes to work end-to-end (observed in practice; not an Adobe-documented SLA). Wait a few minutes and retry before investigating further.
Step 8 — Record the bootstrap in the customer's runbook
For FDE deliveries the bootstrap step is auditable. Record at minimum:
- IMS org ID + name
- Console project name + URL
- Workspace name
- Credential name + creation date + rotation cadence
- The smoke-test response (success / asset URL captured)
- Owner of the credentials on the customer side
Capture these details in your project's onboarding runbook so they are auditable later.
Validate
A bootstrap is complete when all of these are true:
aio console workspace api list --projectName <p> --workspaceName <w> --jsonshows every required service code asACTIVEcurl … /ims/token/v3returns a non-emptyaccess_token- The generate-image smoke test returns HTTP 200 with a non-empty
outputs[0].image.url - The actual generated image renders in a browser
- Credentials are stored in the customer's secrets manager — not in any developer's
.env
If any of these fails, stop and resolve before declaring the engagement live. A half-bootstrapped project is a common cause of week-2 escalations.
Troubleshooting & Edge Cases
aioCLI not installed: Runnpm install -g @adobe/aio-cli. Do not install via Homebrew — the Adobe-maintained npm package is the only supported distribution.- Multiple IMS orgs and the wrong one is selected: Every
aio console *command accepts--orgId <id>. Pass it explicitly when uncertain rather than relying on the default selection. workspace api addreturns "product profile required": The Firefly entitlement is profile-gated. Get the profile name from the customer's org admin and pass--license-config FireflyAPI=<ProfileName>.- Token succeeds but API calls fail 401/403: Check the scope list first. IMS ignores unrecognized scope names rather than rejecting them (verified against the live endpoint), so a misspelled scope still yields a token — minus the entitlement. The full scope set is
openid,AdobeID,session,additional_info,read_organizations,firefly_api,ff_apis,firefly_enterprise,creative_sdk(firefly_enterpriseandcreative_sdkcover Custom Models and Photoshop/Lightroom). Bothfirefly_apiandff_apisare required; they cover different endpoint generations. - Smoke test returns 401 after a successful token call: The token is valid but does not include the Firefly Services entitlement. Check that the project's IMS org and the credential's owning org match.
- First API call returns 403 with no detail: Wait a few minutes and retry. Newly issued credentials can take a few minutes to propagate (observed in practice; not an Adobe-documented SLA).
- JWT credentials still in use: Migrate immediately. JWT reached end-of-life on June 30, 2025 and all certificates expired March 1, 2026 — any remaining JWT integration is already non-functional. Mixed credential types are unsupported.
Chaining with Other Skills
After bootstrap, hand off to:
firefly-services-auth— Production token refresh patternsfirefly-services-rate-limits— Configure rate limits and queueingfirefly-generate-image-v3-async— First real workloadfirefly-services-storage-refs— Set up the asset storage layer