Beacon is a paid self-hosted product. Each install validates a signed beacon.license file against an embedded ECDSA P-256 public key. Validation runs offline — Beacon does not phone home.
This page covers buying, installing, rotating, and the update window for 0.3.3-beta. It does not cover the cryptographic internals.
Buying a license
Licenses for Beacon are sold at apexcode.dev/beacon. Checkout runs through Polar. On completion you get an email with a link to your license portal, where you download the signed beacon.license file plus Docker and Composer install commands.
Tier 1 self-hosted: $149 one-time ($99 during beta).
The license is a one-time purchase and does not expire. The version you buy keeps running whether or not you upgrade.
Updates
Every license includes 12 months of updates from the purchase date. Updates land through your license portal — new tags on ghcr.io/apxcde/beacon and new packages on https://packages.apexcode.dev.
After the year, keep the install you have. New releases require a renewal. Your portal shows the date updates run through.
Installing your license
Drop the file at:
storage/app/beacon.license
The path is fixed (config/licensing.php → license_path). On Docker installs, storage/ is a named volume, so the file persists across container restarts:
docker compose cp ./beacon.license app:/var/www/html/storage/app/beacon.license
On a Composer install from packages.apexcode.dev, copy the file into the project before first boot:
cp ./beacon.license storage/app/beacon.license
Restart the app container to force an immediate re-validation, or wait up to one validation cycle (default: daily).
Test mode
You do not need a license file to develop against a running Beacon with test keys.
Append _test to any API key. While the request carries a _test key, Beacon bypasses license validation entirely (ValidateLicenseOrTestMode) and simulates Twilio without making real calls.
This is the right mode for:
- local development
- CI and integration tests
- evaluating Beacon before you send live SMS
It is not the right mode for production. A _test key is a permission boundary — anyone holding one can drive the system without a license.
Pulling ghcr.io/apxcde/beacon or installing from packages.apexcode.dev still uses the credentials from your license portal.
Validation behavior
| Setting | Default | Effect |
|---|---|---|
LICENSE_ENABLED |
true |
Master switch. Set to false only in development. |
LICENSE_VALIDATION_FREQUENCY |
daily |
How often the cached validation result is refreshed. daily / hourly / always. |
LICENSE_GRACE_PERIOD_DAYS |
14 |
After a license expires, Beacon keeps serving requests for this many days while logging a warning. |
LICENSE_HARDWARE_FINGERPRINTING |
false |
When true, binds the license to one machine. Off by default for self-hosted users. |
LICENSE_AUDIT_LOGGING |
true |
Logs every validation event. |
LICENSE_VERSION_CHECK |
false |
Refuses to run a major version above what the license was purchased for. Used for one-time licenses. |
PRODUCT_VERSION |
unset | Override for the version-check comparison. |
LICENSE_PUBLIC_KEY — also configurable, but do not change it unless you are running a forked distribution. The default value is the public key used to sign every license sold at apexcode.dev/beacon.
What happens when validation fails
| Situation | Behavior |
|---|---|
No license file present, _test key |
Allowed. |
| No license file present, live key | 402 Payment Required from license middleware. |
| License signature invalid | 402 Payment Required. |
| License expired, within grace period | Allowed, with a warning logged. |
| License expired, past grace period | 402 Payment Required. |
License version below installed Beacon version (with LICENSE_VERSION_CHECK=true) |
402 Payment Required. |
The error response carries a JSON body explaining which check failed, so it is safe to surface the message in your tooling.
Rotating a license
To replace an existing license:
- Drop the new
beacon.licensefile atstorage/app/beacon.license, overwriting the old one — or runphp artisan license:install <file>, which also keeps a timestamped backup of the previous license next to it (beacon.license.backup.<timestamp>). - Restart the app container, or wait for the next validation cycle.
Renewals
Renewal extends the update window so the portal will issue newer image tags and Composer packages. The license file you already have keeps the purchased version running after the window closes.
Disabling licensing entirely
For development only:
LICENSE_ENABLED=false
This disables the middleware so any key (test or live) works. Do not ship this setting to production.
Buying source access
If you need to modify Beacon, white-label it, or have compliance requirements that prevent signed-binary models, contact ApexCode for a source-access license. That is a separate agreement and is not covered by the standard beacon.license file.