← Back to Version Route

Marketplace product guide

Version Route Self Help and FAQ

Guidance supplied by Jag Journey, LLC. Find the steps for using this module and answers to common questions below.

Self Help

Version Route

Version Route adds releases and licensing to your website. Your GitLab CI build goes to your website privately. Your software asks your website whether a newer version is out. You sell your software in your own store, every buyer gets a license, and a license is checked before any paid download.

Versioning and updates

Send every build from GitLab CI to your own website. Your software can then ask your website whether a newer version is out.

GitLab CI example

Add these two files to your project. Set the two variables, push a version tag, and your build is on your website.

1. In GitLab, open Settings > CI/CD > Variables and add:

Variable Value
VOVO_SITE Your website, such as https://example.com
VOVO_API_KEY An API key with the hub:write scope. Mark it masked.

2. Add .gitlab-ci.yml:

stages:
  - build
  - release

variables:
  PRODUCT_KEY: my-plugin

build:
  stage: build
  script:
    - mkdir -p dist
    - zip -r "dist/my-plugin-$CI_COMMIT_TAG.zip" src README.md
  artifacts:
    paths:
      - dist/
    expire_in: 1 day
  rules:
    - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/'

send_to_website:
  stage: release
  needs:
    - job: build
      artifacts: true
  script:
    - sh ci/send-to-website.sh "dist/my-plugin-$CI_COMMIT_TAG.zip"
  rules:
    - if: '$CI_COMMIT_TAG =~ /^v[0-9]+\.[0-9]+\.[0-9]+$/'

3. Add ci/send-to-website.sh:

#!/bin/sh
# Sends one built file to your website's File Hub, then publishes the release.
# Needs curl, jq, split and sha256sum on the runner.
set -eu

FILE="$1"
NAME=$(basename "$FILE")
SIZE=$(wc -c < "$FILE" | tr -d ' ')
SHA=$(sha256sum "$FILE" | cut -d ' ' -f 1)
VERSION=${CI_COMMIT_TAG#v}
AGENT="$PRODUCT_KEY-ci/$VERSION"
HUB="$VOVO_SITE/api/v1/hub/uploads"
SOFTWARE="$VOVO_SITE/api/modules/software/v1"
PIECES=$(mktemp -d)

call() {
  curl -fsS -A "$AGENT" -H "Authorization: Bearer $VOVO_API_KEY" "$@"
}

# Start a private upload.
UPLOAD=$(printf '{"filename":"%s","size":%s,"sha256":"%s","visibility":"private"}' "$NAME" "$SIZE" "$SHA" \
  | call -H 'Content-Type: application/json' -d @- "$HUB")
UPLOAD_ID=$(echo "$UPLOAD" | jq -r .id)
CHUNK_SIZE=$(echo "$UPLOAD" | jq -r .chunk_size)

# Send it in pieces, in the order your website asked for.
split -b "$CHUNK_SIZE" -a 4 "$FILE" "$PIECES/piece."
INDEX=0
for PIECE in "$PIECES"/piece.*; do
  call -T "$PIECE" -H 'Content-Type: application/octet-stream' "$HUB/$UPLOAD_ID/chunks/$INDEX" > /dev/null
  INDEX=$((INDEX + 1))
done

# Finish, and read what your website saved.
DONE=$(call -X POST "$HUB/$UPLOAD_ID/complete")
FILE_ID=$(echo "$DONE" | jq -r .file_id)
SAVED_SHA=$(echo "$DONE" | jq -r .sha256)
if [ "$SAVED_SHA" != "$SHA" ]; then
  echo "The website saved different bytes than this job built." >&2
  exit 1
fi

# Publish the release.
printf '{"version":"%s","commit":"%s","notes":"%s","files":[{"file_id":%s,"kind":"app","needs_license":true}]}' \
  "$VERSION" "$CI_COMMIT_SHA" "See the changelog." "$FILE_ID" \
  | call -H 'Content-Type: application/json' -d @- "$SOFTWARE/products/$PRODUCT_KEY/releases"

Push a tag:

git tag v1.2.0
git push origin v1.2.0

When the job is green, open Version Route > Products in your admin. The new version is listed.

Good to know

  • Send your own User-Agent. It makes your calls easy to recognize in your logs, and the server refuses some default client names, such as Go's.
  • Run it again safely. Sending the same bytes for the same version does nothing. Sending different bytes for a version already published is refused. Change the version instead.
  • It is private. Builds sent this way are kept privately in your File Hub. Do not upload a paid build through the File Hub page. Anyone with the address can open a file added there.
  • Size. A build can be up to 500 MB for an archive. Builds count toward your website's storage.

Set up

  1. You need a verified developer account. This is the same account check as all VoVo developer tools. If you are not verified when you go to buy Version Route, you are taken through verification first, then brought back to the purchase. You are not charged before that.
  2. Buy Version Route for your website in the Marketplace. It runs on VoVo, so there is nothing to download, and it installs itself on that website. If the install does not finish, you are told. Open My Purchases and choose Enable for this website to try again.
  3. In your admin, open Version Route > Products and add a product. Its key, such as my-plugin, goes in your CI file and your software. It cannot change later.
  4. Create an API key with the hub:write scope.

Check for a new version

No key is needed, so a free copy can check too.

GET https://example.com/api/modules/software/v1/products/my-plugin/latest?current=1.1.0

Answer:

{
  "product": "my-plugin",
  "update_available": true,
  "version": "1.2.0",
  "released_at": "2026-11-04T18:00:00Z",
  "notes": "See the changelog.",
  "files": [
    {
      "name": "my-plugin-v1.2.0.zip",
      "kind": "app",
      "size": 48211200,
      "sha256": "9f2c...",
      "needs_license": true
    }
  ]
}

Optional filters: channel (default stable), platform and engine.

GET .../products/my-plugin/releases lists past versions, newest first.

Check when your software starts and no more than once a day. Do not check on every action.

Download an update

A free file can be downloaded by anyone. A file with needs_license: true needs a license. See Store and licensing.

Always compare the file's SHA-256 with the answer above before installing.

Publishing more than one file

Upload each file, then list them all in one release:

{
  "version": "1.2.0",
  "commit": "a1b2c3d...",
  "notes": "Fixes a crash on startup.",
  "engine": "5.8",
  "platforms": ["Win64"],
  "files": [
    {"file_id": 512, "kind": "plugin", "platform": "Win64", "needs_license": true},
    {"file_id": 513, "kind": "server", "needs_license": false}
  ]
}
Field Needed Meaning
version Yes Three numbers, such as 1.2.0
files Yes The files you uploaded
kind Yes, on each file What the file is, such as plugin, app or server. It sets the download link's words on the buyer's page. See What buyers get.
needs_license Yes, on each file true for paid files, false for free ones
channel No stable by default. Use beta for a test group.
notes No Shown to your buyers
commit, engine, platforms, released_at No Kept with the release and returned by latest
known_hashes No SHA-256 of your program files. See Tamper flags.

Withdraw a bad release

Open the product in your admin and choose Withdraw on the release. It stops being offered and downloaded, and latest falls back to the version before it. Nothing is deleted. To replace it, publish a new version.

Errors

Answer Meaning What to do
401 The key is wrong or missing Check VOVO_API_KEY
403 The key lacks hub:write, belongs to another account, or its owner is not a verified developer Use a hub:write key from a verified developer on this website's account
404 Unknown product, or the module is not on this website Check PRODUCT_KEY and VOVO_SITE
422 file_not_private A file in the release was not sent to this website through the upload calls Upload it with the calls above, never through the File Hub page
409 version_exists That version has different bytes Use a new version
413 The file or a piece is too large Use the chunk_size your website gave you

Store and licensing

Sell your software in your own store. Every buyer gets a license. Your software checks that license on your own website before any download is given.

How it works

  1. A buyer pays in your store.
  2. They get a license key by email. The key and the download also show under My licenses in their account, and on that order's page under Purchases. They download their first copy from either place. Both need a signed-in account with a verified email, and the account's email must be the one on the order.
  3. They enter the key in your software.
  4. Your software calls your website. If the license is good, it gets a download.

Every address is on your own domain.

Set up a product for sale

1. Take payments. Your store needs a connected payment account. Sales go to your account, less the platform fee.

2. Create a store product for each way you sell. For example, one for 3 months, one for 12 months and one for lifetime. Set the type to Digital and set your price.

Each Digital product must have a download file. Attach a short Getting started PDF, not your software. Your software stays private in Version Route, where each download is checked. A file attached to a store product stays with that order and goes out of date.

3. Add a plan for each store product. Open Version Route > Products, choose your product and add a plan:

Setting Choices
Store product The product you just made
Length A number of months, or lifetime

4. Choose what happens when a license ends. Set this once per product:

Setting What happens
Downloads stop Your software keeps running. The buyer cannot download anything.
Software stops Downloads stop, and your software is told to stop. Your software must do this itself. See Stopping your software.

If you choose Software stops, also set Offline days: how long a paid-up copy keeps working with no connection.

5. Publish your license terms. Add your terms to the store product with AgreeRoute, so each buyer accepts them before paying. If your software stops when a license ends, say so plainly on the store page and in your terms.

What buyers get

Situation Result
Buys for the first time A new key by email
Buys again with time left New time is added to the time they have. The key stays the same.
Buys again after it ended The same key works again, starting from the purchase
Buys a lifetime plan The end date is removed
Time runs out All downloads stop, including older versions
Full refund That order's time comes off the license. A license with nothing paid left is cancelled at once.
Chargeback The license is cancelled at once

Both places show the same table: the software, the key with a Copy button, its status, its end date, the computer in use and the downloads. The newest stable version is offered. A file of kind plugin or app reads Download plugin or Download app. Any other file, or a second file of the same kind, shows its file name.

One license works on one computer and is locked to it. To move to a new computer, a buyer frees the old one from My licenses, up to 3 times in 12 months, so a new PC does not need a support ticket. You can free one for them at any time.

Under Version Route > Licenses you can search licenses, issue one by hand, restore one, and see which computers are in use.

Cancel a license

Open the license and choose Cancel license. Give a reason. The action is logged. Downloads stop at once, and the buyer's copy is told at its next check. A copy that stays offline hears nothing until its lease runs out.

Add licensing to your software

All calls go to your own website:

https://example.com/api/modules/software/v1

Send the key in a header. Never put a key in an address.

Authorization: Bearer LIC-XXXXX-XXXXX-XXXXX-XXXXX
User-Agent: my-plugin/1.2.0
Content-Type: application/json

Send your own User-Agent, so your software is easy to recognize in your logs. The server refuses some default client names, such as Go's.

Activate

Call this when a buyer enters their key. It locks the license to this computer.

machine_id must stay the same on one computer and must not identify the person. Hash a machine id with your product key, and never send the raw value.

curl -fsS -A "my-plugin/1.2.0" -H "Authorization: Bearer $LICENSE_KEY" -H "Content-Type: application/json" -d '{"product":"my-plugin","machine_id":"3f1c...","machine_name":"Studio PC"}' https://example.com/api/modules/software/v1/licenses/activate

Answer:

{
  "status": "active",
  "plan": "Until Nov 4, 2027",
  "ends_at": "2027-11-04T18:00:00Z",
  "moves_left": 3,
  "when_ended": "software_stops",
  "lease": "eyJ2Ijox...",
  "lease_expires_at": "2026-11-11T18:00:00Z"
}

ends_at is null for a lifetime license, and plan then says Lifetime. moves_left is how many more moves this buyer has in the current 12 months.

Check

Call /licenses/check with the same body when your software starts, and once a day. It returns the same answer and a fresh lease. It does not use a move.

You can also send file_hash, the SHA-256 of your running program. See Tamper flags.

Do not make a person wait for this call. Run it in the background.

Free a computer

Call /licenses/deactivate with the same body to free this computer. It uses one of the buyer's moves.

Download

Ask for a link, then fetch it. The link lasts 10 minutes and can be used again in that time, so an interrupted download can resume.

curl -fsS -A "my-plugin/1.2.0" -H "Authorization: Bearer $LICENSE_KEY" -H "Content-Type: application/json" -d '{"product":"my-plugin","version":"1.2.0","file":"my-plugin-v1.2.0.zip","machine_id":"3f1c..."}' https://example.com/api/modules/software/v1/downloads

Answer:

{
  "url": "https://example.com/api/modules/software/v1/downloads/8Qz1...",
  "expires_at": "2026-11-04T18:10:00Z",
  "size": 48211200,
  "sha256": "9f2c..."
}

Fetch the url with no key. Compare the SHA-256 before installing.

Answers when it fails

Show message to the person. Use error in your code.

Answer error Meaning
401 license_invalid The key is wrong, or for another product
403 license_expired Time ran out. renew_url is included.
403 license_cancelled Refunded, charged back or cancelled by you
403 other_computer_active This license is on another computer. manage_url is included.
403 move_limit_reached No moves left. Send the buyer to support.
403 computer_not_activated Call activate first
404 file_not_found That version or file is not available
410 link_expired The download link ended, or the license stopped. Ask for a new link.
422 invalid_machine_id Send a machine_id of 16 to 128 letters and numbers
429 too_many_requests Wait and try again
429 report_limit_reached This license has sent its reports for today

Do not treat a network failure as a bad license. A paid buyer on a plane has done nothing wrong. Use the lease.

The lease

A lease lets a paid-up copy run with no connection. It is a signed note from your website saying this license is good until a set time.

base64url(payload) + "." + base64url(signature)

The payload is JSON:

Field Meaning
v Format version, 1
kid Which signing key was used
lic The license's public id
prd Your product key
mch The machine_id
sts active
iat When it was issued, in Unix time
exp When it stops being valid, in Unix time

To check a lease in your software:

  1. Split the lease at the dot and decode both parts. Verify the Ed25519 signature over the decoded JSON bytes with your public key. It is on the product page in your admin. Build it into your software.
  2. Check that prd and mch match.
  3. Check that the time now is before exp.

exp is never later than the license's end date, so a copy stops on time even with no connection.

Stopping your software

Only if you chose Software stops.

Your website does not reach into a buyer's computer. It tells your software the license has ended, and your software must act. A good stop:

  • Never crashes, and never blocks anything else from opening.
  • Never touches the buyer's own work.
  • Says clearly why it stopped, and gives a link to renew.
  • Starts working again as soon as a new lease arrives.

Be honest about what this does. If you ship source code or an unprotected app, a determined person can remove your check. The check on your website is the real gate: nobody downloads without a license.

Tamper flags

A flag tells you something looks wrong. A flag never cancels a license on its own, because a false match would shut off someone who paid.

A flag is raised when file_hash is not in the known_hashes of any release, or when a license keeps being tried on other computers. Flags show on the license and on any bug report from it. If you agree it is a problem, cancel the license yourself. Say in your terms whether that gets a refund.

Bug reports

Your software can file a support ticket on your website. It sends the report with the license key. Your website checks the license and adds the buyer's name and email from their order, so your software never holds them and never holds a VoVo token.

curl -fsS -A "my-plugin/1.2.0" -H "Authorization: Bearer $LICENSE_KEY" -H "Content-Type: application/json" -d '{"product":"my-plugin","machine_id":"3f1c...","version":"1.2.0","signature":"crash-7a41","summary":"Crash while saving","details":"Stack and log text"}' https://example.com/api/modules/software/v1/reports

Answer:

{
  "ticket": 1042,
  "repeat": false,
  "count": 1
}

signature identifies the bug. Build it from the call stack or the error. One signature on one license makes one ticket, and repeats add to its count. Each license has a daily cap. The buyer gets one email for each new bug and none for repeats.

Never send keys, passwords or your buyer's files. Clean log text before sending it, and keep a report under 10 MB.

Automatic reports are on by default. Show a notice on first run, give the buyer a setting that turns them off, and say so on your privacy page.

Your buyers' data

Version Route keeps each buyer's email, their license, the computers they use, a record of downloads and their bug reports. Download records are removed after 90 days. These are part of your website's customer export. Mention them in your privacy page.

Need help?

Open Get Help on Version Route in your admin to reach the support ticket center.

Frequently asked questions

Version Route FAQ

Is this a download I install on my own server?

No. Version Route runs on VoVo. You buy it for one website and it installs itself on that website. If the install does not finish, you are told, and Enable for this website in My Purchases tries again.

Why must I be a verified developer to buy it?

Version Route works through a developer API key, and VoVo gives those keys to verified developers only. That keeps scammers and spammers out. If you are not verified, you are taken through verification first and sent a link back to the purchase. You are not charged before that. Verification can take a few days.

Do my own buyers need to be verified?

No. Your buyers need only a license.

Can anyone download my paid build?

No. A paid build sits on a private disk with no public address. A download needs a valid license, from the buyer's own signed-in My licenses page or order page, or from an activated computer, and the license is checked again when the file is fetched. Never upload a paid build through the File Hub page, because a file added there can have a public address.

Where do my buyers find their key and download?

The key comes by email. The key and the download also show under My licenses in their account and on the order's page under Purchases, with a button that copies the key. Both pages need a signed-in account with a verified email, and the account's email must be the one on the order.

Can VoVo support see a buyer's key?

No. In a support session a key shows only as its last four characters, with no copy button. Support can use the same download links as the buyer, so they can check a file, and each download is recorded on the license like any other.

What happens when I press Cancel license?

You give a reason and it is logged. Downloads stop at once, including links already given out. The buyer's copy is told at its next check. A copy that stays offline stops when its lease runs out.

Can a fake local server tell my software a license is good?

No. Your software checks each lease against your public key, and only your website holds the private key.

Does a tamper flag cancel a license?

Never. A flag only tells you something looks wrong, because a false match would shut off someone who paid. You decide.

What happens on a refund or a chargeback?

A full refund takes that order's time off the license, and a license with nothing paid left is cancelled. A chargeback cancels the license. A partial refund leaves the license as it is. You can restore a license by hand. A payment made in test mode issues no license.

How many computers does a license cover?

One, and it is locked to that computer. A buyer can move it 3 times in any 12 months from My licenses or from your software. You can free a computer at any time, and that does not use a move.

What if a buyer buys again?

New time is added to the time they have, and the key stays the same. A lifetime purchase removes the end date. Buyers are matched by email address.

Does my software need a VoVo token to send bug reports?

No, and it must never hold one. It sends the report with its license key. Your website checks the license and adds the buyer's name and email from their order.

Why did a repeat of the same bug not make a new ticket?

One bug on one license makes one ticket, and repeats add to its count as a private note. The buyer gets one email for each new bug and none for repeats.

Do builds use my storage?

Yes. Builds count toward your website's storage. Removing old builds from File Hub is your choice, once no release needs them.

What file types can I publish?

Archives such as zip and tgz, and disk images, up to 500 MB for an archive.

Where do I get help?

Open Get Help on Version Route in your admin to reach the support ticket center.

Still need help?

If you acquired Version Route, open your VoVo website admin and choose Get Help beside it in Marketplace Modules. The product developer answers those tickets inside VoVo. VoVo administrators can review and assist. Use platform support to report a product or developer concern, not for routine feature help.