This page is for developers who sell their own extensions through Release Manager. It shows how your customers can link their site to their account on your store, so that your paid updates install from Joomla's own update screen. For setting up the store itself, see the Release Manager documentation.

Start here

You don't need to read this whole page. In your store's Release Manager, go to Packages and click Add licensing to your extension under your package. That screen has the routes below with your store URL, element and product name already filled in, and it checks that the package's settings are ready. It needs Release Manager 1.15.0 or later.

The Add licensing to your extension screen: a checklist of the package's settings, the manifest lines for the download key route, the form that generates a kit, a prompt for an AI assistant, and the paid service last ⤢ Click to enlarge
Every route on one screen, filled in for one package.

Pick a route

RouteWhat you doWhat your customer doesWorks for
1. Download key Add a few lines to your manifest Gets a key from your store and pastes it into Joomla Any extension type, including modules
2. Generated kit Download a zip, copy files in, paste a few lines Types their email into your extension Components and plugins
3. AI assistant Paste a prompt into Claude Code or similar, then review Types their email into your extension Components and plugins
4. We do it Send us your extension Types their email into your extension Anything

The first three are included with your licence. You can start with the download key and add a Link your account screen later: they work side by side.

Route 1: a download key

Add this to the manifest of what you sell. The Add licensing screen has it with your real address in it.

<updateservers>
  <server type="extension" name="My Extension">https://your-store.example/index.php?option=com_csreleasemanager&amp;task=api.updatexml&amp;format=raw&amp;element=pkg_myextension</server>
</updateservers>
<dlid prefix="dlid=" suffix="" />

Your customer then:

  1. Logs in to your store and opens the My Installations page.
  2. Under Add a site, chooses your extension, types the site's domain and clicks Add site.
  3. Opens Download key on the new row and copies the key.
  4. On their site, goes to System → Update Sites, opens your extension's entry and pastes the key into Download Key.
The My Installations page with a site's Download key open, and below it the Add a site form with a package list, a domain box and an Add site button ⤢ Click to enlarge
Your customer adds a site and copies its key on My Installations.

Site limits, the customer's own blocked domains and your blacklist apply just as they do to any link. To turn this off, set Options → Customers Can Create Download Keys to No. Your store needs a published menu item for My Installations.

Remote site managers. Joomla only sends a pasted key with the download, so mySites.guru and similar tools won't have it when they read the update feed. If your customers use those, the Link your account routes below are the better fit, because they also put the key in the feed address.

Route 2: a generated kit

On the Add licensing screen, fill in your extension's type, element and namespace and click Download the kit. You get a zip of ready-made files with your details in them, plus a README with the exact steps. It only adds files: none of your existing code changes except your manifest and install script.

  1. Copy the files in. For a component, the new files are a client class, a panel, a small controller, a Link your account screen and a language file. For a plugin, they are the client, the panel, a form field and a language file.
  2. Paste the manifest lines from snippets/manifest.xml. They add the menu entry or settings tab, the update server and the download key.
  3. Paste the install-script lines from snippets/postflight.php. Joomla rebuilds the update site when your extension updates, and these put the key back in its address.
  4. For a plugin, add one method from snippets/plugin-method.php. The panel posts through Joomla's com_ajax, so the plugin has to be enabled to link.

Change the wording in the kit's .account.ini file and the layout in account-panel.php as much as you like. The link is kept in your extension's custom_data column in #__extensions, under the key csrm_account, so saving your Options and updating your extension both leave it alone.

Prefer the command line? The same generator is in the public client kit, along with finished examples of a component and a plugin.

Route 3: let an AI assistant do it

Open your extension's code in Claude Code or a similar coding assistant and paste the prompt from the Add licensing screen. It looks like this:

Add licence linking to this Joomla extension by following the instructions at
https://raw.githubusercontent.com/cybersalt/release-manager-client-kit/main/INTEGRATE.md

Store URL: https://your-store.example
Store name: Your Store
Package element: pkg_myextension
Feed key: (none)
Product name: My Extension

The instructions tell the assistant how to read your manifest, generate and apply the kit, and what not to touch. It reports what it changed and how to test it, and it doesn't commit or publish anything unless you ask. Review its changes as you would anyone's.

Route 4: have us do it

If you'd still rather not touch the code, Cybersalt can add it to your extension and test it against your store for a fixed fee. See the integration service.

The store's side

Whichever route you take, the package needs these. The Add licensing screen shows which are missing.

  • Public / Free Extension set to No, and the Allowed User Groups your membership plan puts buyers into.
  • Renewal URL and Renewable User Groups, so expired customers get a Renew button instead of a dead end.
  • Sign-Up URL, for the Buy button people see when they aren't customers yet. Options has a default for packages without one.
  • Account Link Location: where your panel is, written to fit a sentence (for example in Components > My Extension > Link your account). Joomla's update screen uses it to tell a customer where to link. Options has a default for this too.
  • A Store Name in Options, if customers know your store by something other than your site's name.

What your customer sees

Answer from the storePanel shows
activeGreen badge; updates arrive under System → Update → Extensions.
lapsedThe store's message and a Renew button (the package's Renewal URL).
not_a_memberThe store's message and a Buy button (the package's Sign-Up URL, the store's Default Sign-Up URL, or the Renewal URL).
over_limitEvery site the licence allows is in use.
blacklistedBlocked; contact support. No retry form.

Why linking needs no email confirmation

Anyone can type any address into the panel, and nothing asks them to confirm they own it. That is on purpose. Your extension is open source, so nobody can be stopped from running it, and a confirmation step would only make it harder for honest customers. Linking gives you and the address's owner what's needed to deal with it instead:

  • The address's owner finds out. They get an email naming the domain as soon as a site links to their address. On My Installations they can deactivate or remove the site, or report it as one they don't recognise, and the domain can't link to that address again.
  • You get a lead. Every site that registers shows under Installations with its domain, even if it never pays. Filter by status or by Update Access to find sites using your extension without a licence, and write to them about buying one.
  • Only entitled addresses get updates. A link only opens updates when the address belongs to a customer in an allowed group, and site limits count against that customer.

Testing it

The kit includes test-link.sh, filled in for your store: sh test-link.sh This email address is being protected from spambots. You need JavaScript enabled to view it.. It runs these same calls, which you can also run by hand. Replace the store, element and email:

STORE=https://your-store.example
ID=20261030120000_test.example.com_0123456789abcdef
HASH=$(printf %s "This email address is being protected from spambots. You need JavaScript enabled to view it." | sha256sum | cut -d' ' -f1)

curl -s -H "Content-Type: application/json" \
  -d "{\"installation_id\":\"$ID\",\"package_element\":\"pkg_myextension\",\"domain\":\"test.example.com\"}" \
  "$STORE/index.php?option=com_csreleasemanager&task=api.register&format=json"

curl -s -H "Content-Type: application/json" \
  -d "{\"installation_id\":\"$ID\",\"email_hash\":\"$HASH\",\"email\":\"This email address is being protected from spambots. You need JavaScript enabled to view it.\"}" \
  "$STORE/index.php?option=com_csreleasemanager&task=api.linkemail&format=json"

curl -s "$STORE/index.php?option=com_csreleasemanager&task=api.verifyaccess&format=json&dlid=$ID:$HASH"

curl -s "$STORE/index.php?option=com_csreleasemanager&task=api.updatexml&format=raw&element=pkg_myextension&dlid=$ID:$HASH"

For an entitled email, verifyaccess answers "state":"active" and the update feed's download URL carries the dlid. Delete the test installation from Installations afterwards.

Rules worth keeping

The kit already does all of this. Keep it that way if you change the client, or do the same if you write your own.

  • Only touch your own update site. Match it by your store's host and your element. Other vendors' extensions on the same site have their own keys.
  • Escape the store's messages. They are shown to an administrator in your customer's Joomla, and Joomla prints system messages as HTML.
  • Save the installation ID only after the store accepts it. An ID saved before a failed registration leaves the site sending an ID the store has never seen.
  • Make the random part long. The timestamp and domain can be guessed and the email hash is easy to work out, so the random part is the key's only secret. The client uses 16 hex characters.
  • Put the key back after updates at the end of the request. Joomla rebuilds the update site after your postflight() has run. It keeps the key in extra_query but not in the address, so writing it in postflight() itself does nothing for remote managers.

Writing your own client

If none of the routes suit, these are the calls, all on your store at index.php?option=com_csreleasemanager&format=json&task=…:

  1. Make an installation ID in the form <digits>_<domain>_<random hex> (up to 100 characters).
  2. api.register: POST JSON {"installation_id", "package_element", "domain"}. Save the ID when this returns 200 or 201.
  3. api.linkemail: POST JSON {"installation_id", "email_hash", "email"}, where the hash is SHA-256 of the lower-cased email.
  4. api.verifyaccess&dlid=<id>:<hash>: the status to show.
  5. Write dlid=<id>:<hash> to your update site's extra_query, and append it to the update site's location too: Joomla only sends extra_query with the download, and remote managers such as mySites.guru need the key in the feed URL.

Getting help

Ask through the Cybersalt support form, with your store URL and your package's element.

Add licensing to your extension — click anywhere to closeClose × The Add licensing to your extension screen Add a site on My Installations — click anywhere to closeClose × The Add a site form on My Installations