Skip to content

Firefox Add-ons ​

Firefox submissions go through the AMO API v5. Reach for this page when you set up the AMO credentials, choose between a listed and an unlisted channel, or need the source archive and data collection declaration a review asks for.

Quick start ​

bash
curl -s -X POST https://www.extension.dev/api/cli/stores/submit \
  -H "Authorization: Bearer $EXTENSION_DEV_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"browsers":["firefox"],"buildSha":"<sha>","channel":"stable"}'

The platform creates an upload, polls its validation, then creates the version from it. The same submission starts from the console's Submissions tab or from an agent with extension_submit.

How it works ​

Credentials ​

AMO authenticates with a JWT signed from an issuer and a secret. The platform mints the JWT per request with a 30 second expiry, so the secret never travels and a captured token dies fast. Add the key and secret in the console under Project settings, Store publishing, Firefox.

Listed and unlisted ​

AMO has its own channel concept, separate from Extension.dev release channels. The AMO channel is the Automated release channel setting in the project's Firefox store settings, and it defaults to unlisted. A submission with no channel saved goes unlisted, never listed.

unlisted is how to get a signed build for self distribution without a public listing.

The first submission ​

A first submission cannot be listed without an existing add-on GUID. It either goes unlisted or creates a new add-on. When AMO assigns the GUID, the platform writes it back to the project's Firefox settings, so the second submission already knows its add-on.

Source code uploads ​

AMO rejects a listed review of a bundled or minified build that carries no sources, and every build the platform produces is bundled. Set Source archive to Attach the repository at the built commit in the project's Firefox store settings. Every Firefox submission then carries a zip of the source repository at the commit that produced the build.

The archive is packaged during the submission and attached to the version for Mozilla reviewers. The setting is off until you turn it on.

Reviewers also need the steps that turn that source into the submitted build. Those come from STORE.md, which is submitted as the reviewer note.

The console's readiness checklist warns when a project has no archive configured, on either channel: a listed review rejects a version without sources, and an unlisted version is signed unread but Mozilla's policies still apply to it, so a reviewer can ask for the sources or block the add-on later. The dry run on the submit call does not read this setting. The warning is advisory. AMO is what rejects.

Reviewers rebuild from the archive on their own machine, with Node 24 on Ubuntu unless the note says otherwise, so the reviewer note in STORE.md names the Node version the platform built with (22 unless the project set one), the install command against the lockfile, the build command and the output directory.

AMO requires every add-on to declare data collection permissions in the manifest, under browser_specific_settings.gecko.data_collection_permissions. An extension that collects no data still declares {"required": ["none"]}. AMO rejects a new add-on without the key, and Mozilla has announced that every existing extension must adopt it during 2026. The data collection permissions documentation on Extension Workshop has the shape.

The preflight reads the key from the Firefox build under submission (manifest.json inside its stored zip). When that build left no readable artifact, it reads the source manifest at the build's commit with the Extension.js firefox: and gecko: prefixes resolved the way the build resolves them, and the check names the file it read either way.

The platform warns twice. A dry run on any project targeting Firefox returns a FIREFOX_DATA_COLLECTION_PERMISSIONS warning, and the submission logs a warning when the uploaded package's manifest.json is missing the key. Both are advisory. AMO is what rejects.

The one refusal is a package whose manifest.json cannot be read out of the zip at all. That submission stops with FIREFOX_DATA_COLLECTION_UNVERIFIED before anything is uploaded.

Reviewer notes, release notes and category ​

Firefox reviewer notes and release notes are read from STORE.md in the project root and submitted automatically. See Publishing.

The - Category: line under ## Listing is shared by every store, and AMO has fewer categories than the Chrome Web Store: it has no Accessibility and no Productivity. When the shared name is one AMO lacks, put a - Category: line under ## Firefox Add-ons with one of AMO's own names; Other is the closest when none fits. The per-store line wins for Firefox and leaves the other stores on the shared one.

An unlisted upload needs no category. AMO signs the file for self distribution and the listing is never sent, so the preflight only warns. A listed submission is refused by AMO after the file is sent when the add-on has no AMO category, so there the preflight blocks until STORE.md names one.

Watching ​

The Submissions tab follows the submission to a terminal state, and GET /api/projects/{id}/stores/status returns the same. The states are the eight on Publishing. Firefox tracks by the version id the submission returns.

Reference ​

Secrets ​

ValueSecretNotes
API key (issuer)STORE_FIREFOX_API_KEYFrom the AMO API credentials page
API secretSTORE_FIREFOX_API_SECRETShown once, at creation

Store settings ​

SettingStored asValues
Add-on GUIDstoreIdEmpty for a first unlisted submission, written back by the platform
Automated release channelreleaseChannelunlisted (default) or listed
Source archivesourceArchivenone (default) or repository

AMO channels ​

AMO channelResult
listedPublished on addons.mozilla.org, goes through review
unlistedSigned and returned to you, not listed publicly

Warnings and refusals ​

CodeKindMeaning
FIREFOX_DATA_COLLECTION_PERMISSIONSWarning when the Firefox manifest of the build lacks itDeclare data_collection_permissions in the manifest; the warning names the file it read
FIREFOX_DATA_COLLECTION_UNVERIFIEDRefusal before uploadmanifest.json could not be read out of the zip

When it fails ​

  • Validation fails. Validation failures surface while the upload is polled, before a version exists. Read the validation messages. The version was never created.
  • A first submission asks for listed. It is refused by design. Submit unlisted or let it create the add-on, then go listed once the GUID exists.
  • A store is blocked. The preflight, dryRun on the submit call, reports credential health and the console page that fixes a blocked store.
  • The submission stops with FIREFOX_DATA_COLLECTION_UNVERIFIED. The package's manifest.json could not be read. Rebuild the package and submit again.

Next ​