Skip to content

Licensing

Heinzel Pro is sold as a subscription. The installation checks a signed license key offline. Four times a day it fetches a renewed key from heinzel-pro.de, sending only the key it holds; that can be switched off. What an installation does connect to is listed in security.md, "What leaves the installation".

The license page and the Operations box under Installation, Log say when that last worked, or since when and why it fails. After a day of failing the installation's administrators get one mail, and in the last 14 days before the key's day a banner shows them on every page. The way out is HTTPS (port 443) to heinzel-pro.de, or the key from the mail entered by hand.

For customers

  • Without a key, the installation runs a 14-day trial with three seats.
  • A seat is any enabled member or administrator of a tenant, one who only looks too. An open invitation takes none until it is accepted.
  • After the key expires there is a 14-day grace period with a banner. After that, no new sessions or scheduled runs start; everything recorded stays readable.
  • Keys are pasted under Settings, License.
  • The key carries one number of seats for the whole installation. Where the installation holds several tenants, each can be given a number of its own below that, see administration.md, "Seats per tenant". A person counts once against the key, however many tenants they act in. Servers work the same way: the key carries one number for the installation, and each tenant can be given its own below it.

Tariffs

An installation begins with five tariffs. They are presets: what a tenant gets is its own copy, and a tariff changed later leaves it as it is (see administration.md, "Tariffs").

TariffSeatsServersParallel sessionsSeveral serversAPI
Free111nono
Solo151yesno
Team3202yesno
Business3520010yesyes
Enterprise10060030yesyes

The parallel sessions are shared by everybody in the tenant, however many seats it has. It counts every session Heinzel is working on, a rollout's and a schedule's too: a rollout on three servers at a time takes three. A session waiting for an approval or for the next message does not count, and an approved command goes on even when all are at work.

When all are at work, a new request is not refused. The message box says so before it is sent; the request then waits in line, oldest first, its session shows its number in line with "Take it back", and it starts once another session is done, after a restart too. Nobody has to stay on the page for that.

Rollouts and schedules over several servers take only sessions nobody waits for: people's messages always go first. A rollout runs on up to four servers at a time when so many are free, on fewer otherwise; one of its servers always runs, so that a full day slows it down but never stops it. Sessions that work together start at once, so they need a free session for each server when they start.

The Running tab of the sessions list shows how many are taken, such as "4/4", and beneath it two parts: what is at work, and what waits for a free session in the order it gets one, people's requests first, then the servers of each rollout or schedule, one line each. A mark for each session shows by its colour whose it is: a person's, a rollout's or a schedule's. The dashboard shows the same parts under "Running sessions"; the page of a rollout waiting for free sessions says so and gives its number in line.

Since 30 October 2026 the parallel sessions above hold for tenants that ordered before as well, and on the hosted installation the seats and servers too. A limit set lower by hand stays, and no tenant loses a seat or server it already uses. A Team tenant with a valid API token keeps the API.

Without the API, the interface refuses every token with 403 and says why. The tokens are kept and work again once the tariff includes the API.

Without "Several servers" a session works on one server. Under New session, "Several together" and "The same on many" stand greyed, with a link to the tariffs; a rollout and a session over several servers are refused.

Free counts working time: 1 hour per calendar week (Monday 00:00 to Sunday, Berlin time), from the first day. It counts while Heinzel works or somebody has a page of the tenant open in front of them; each moment counts once, even with two sessions running or somebody watching their own session. A tab in the background counts nothing, nor does a session waiting for an approval, for the next message or behind another session, nor a restart or a crash. Once the hour is used up, the pages stay open and a session that exists goes on; only a new session (from a person, a schedule or an alert) and a new schedule wait for the next week. The New session button stands greyed then. Beneath it, "Time left in the Free plan" counts the week's minutes down to the next reset, whose date and time stand beneath, green above half, yellow above a fifth, red below; on a phone the bar on top shows the same count. Nothing counts until a model is connected and Heinzel has signed in to a server; a server still being set up does not count. Until then the box stands still in grey. The other tariffs count no time.

Ordering and changing the tariff

On a hosted installation a tenant's administrators order under Settings, Tariff themselves: the tariff, by the month or the year (ten monthly prices). Each price includes the tariff's seats, nothing is added by the seat: Solo 1, Team 3, Business 35, Enterprise 100. Before ordering, the page says what it costs. All prices are net, plus VAT where it applies. The form asks for the invoice address and, if there is one, the VAT number; it keeps them for the next order.

  • Period day. A subscription begins on any day; that day is its period day, and every period begins on it. Where a month lacks it, the period begins on the month's last day, and on the period day again after. A period costs the full price whether it has 28 or 31 days.
  • Up (a larger tariff, more seats, month to year) holds at once. The rest of the period is settled by the day: the new price minus the old, each for the days left.
  • Down holds from the next period, with nothing paid back, and only once seats and servers fit into the smaller tariff; otherwise the page says what is too much. Until then, "Keep …" takes the change back.
  • Paying. The tariff holds at once, for 45 days at first. The invoice comes by mail; marked paid, it holds to the end of the period. 14 days after the last paid day a tenant falls back to Free.
  • Price lists. A price is never changed; the database refuses it. New prices are a new list for new orders, and every order keeps the amount it was placed with. Installation, Prices shows the list on sale and sells a new one; the list on sale is at /api/prices for the website.

The installation's administrators see the orders under Installation, Orders, where they mark an order paid: each click settles the oldest period still open, the first one and then each one invoiced after it, so a late payment never covers a later period. HEINZEL_SALES_TO names the address that gets every order by mail, and every cancellation, invoice due and invoice left to a person. Each such mail ends with everything about the customer and the order: the tenant and when it was made, the invoice address and VAT number, who ordered and every administrator with their address, the tariff, price and payment method, when it was ordered, paid, cancelled and by whom, when it ends, and each payment, all with the time of day, so you can ask the customer whether all is well. It also gets, on the first of each month, a report on the month before: orders, cancellations, what runs and what it brings a month, what Stripe collected, and how many tenants, people, servers and sessions there were.

Ordering a license to run it yourself

Under Settings, Tariff, "On-premises" switches to the prices for running Heinzel Pro on your own servers; Business and Enterprise have them, Team runs with us only. Such an order runs beside the tenant's tariff, changes nothing about it, and comes with a signed license key, shown right on the same page and downloadable as a file. It holds 45 days while the order is not paid yet, then four weeks past the last paid day, as a buffer should heinzel-pro.de be down for a while or a payment come late. Every paid period brings a new one on the page, and your own installation fetches it by itself. By mail to the tenant's administrators comes the first key of an order, a renewed one only if the installation has not fetched it after a week. Paying by invoice, you get a key to four weeks past the end of each period when it begins, before the invoice is paid; the mail to HEINZEL_SALES_TO reminds to write it. On your own installation it goes under Installation, Settings, License, and holds there 14 days past its day.

Cancelling

An administrator cancels the tariff or the license on the same page, to the end of the running period. Everything holds until then; after it nothing is collected and no key is signed, and a tenant falls back to Free at once. Until the last day the cancellation can be taken back. The mail to HEINZEL_SALES_TO names the day it ends.

For the operator: keys are signed with HEINZEL_LICENSE_PRIVATE_KEY, the private half of the key pair below. It belongs on the hosted installation only, never on a customer's. Without it the installation signs nothing, and the mail to HEINZEL_SALES_TO says to issue the key by hand.

Paying by card or direct debit

Under Settings, Tariff a tenant's administrators set up a card or a SEPA direct debit mandate, on Stripe's own page; Heinzel Pro learns only which one it is ("Visa •••• 4242"). From then on every order is collected: the amount due at once, the full amount when each later period begins. A period counts as paid only once Stripe says so, at once for a card, after some days for a debit. When a collection fails, the page says why; the tariff then holds for 14 days as with an unpaid invoice, and a newly set up card collects the amount again.

Prices are net. Stripe collects them with VAT as the invoice address calls for it: 19 % in Germany and for a person elsewhere in the EU, none for a business elsewhere in the EU with a VAT number (reverse charge) or for anybody outside the EU. Stripe only collects the money; sevdesk writes the invoice and mails it at once to whoever placed the order, as an e-invoice that says it is paid.

For the operator: STRIPE_SECRET_KEY turns it on, and STRIPE_WEBHOOK_SECRET is the signing secret of the webhook https://<host>/api/stripe/webhook with the events payment_intent.succeeded, payment_intent.processing and payment_intent.payment_failed. Which payment methods Stripe offers is set in the Stripe dashboard: create a payment method configuration of its own there with only card and SEPA direct debit, and enter its id (pmc_…) as STRIPE_PAYMENT_METHOD_CONFIGURATION. Without it Stripe offers everything the account's default configuration holds, including methods that cannot be collected unattended.

SEVDESK_API_TOKEN, the API token of a sevdesk administrator, lets sevdesk write those invoices. Without it, or when an invoice address names a country Heinzel Pro does not know the VAT for, or when sevdesk refuses an invoice ten times over, the mail to HEINZEL_SALES_TO says to write it by hand. An invoice is not booked as paid in sevdesk; match it with the Stripe payout there. With a test key (sk_test_…) nothing is invoiced: test money is no revenue.

For the vendor

Keys are Ed25519 signatures over a JSON payload. Generate the signing pair once:

$ mix heinzel.license keygen

Put the public key into the build (config :heinzel_pro, :license_public_key) or set HEINZEL_LICENSE_PUBLIC_KEY on customer installations. Keep the private key offline; the one exception is the hosted installation, which signs the key of an order itself (HEINZEL_LICENSE_PRIVATE_KEY).

Issue a key:

$ mix heinzel.license issue --customer "ACME GmbH" --plan team --seats 5 \
  --expires 2027-12-31 --private-key "$HEINZEL_LICENSE_PRIVATE_KEY"

Verify one:

$ mix heinzel.license verify HPL1....

Plans: team, business, enterprise. The payload also carries an optional server count and feature list for future use.

Source code for individual customers

Heinzel Pro is not open source software. Individual customers get the source code to read and change, under LICENSE.md, and may send changes back as pull requests. What they send back is sold to every other customer, so the rights to it are settled before anybody merges it:

  1. The customer's contract grants the access in writing.
  2. The customer returns the contributor agreement signed (the German text, docs/de/contributor-agreement.md), with the GitHub accounts of its people in the annex. It is kept outside the repository.
  3. The accounts go into .github/contributors. The check contributors fails a pull request while the person who opened it, or the author of one of its commits, is missing there.
  4. The accounts get the role "Read" on GitHub.

Step 4 requires the repository to belong to an organization. A repository of a personal account knows only collaborators with write access: whoever is invited there can push to main, merge pull requests and set a tag, and a tag builds the image and deploys it to the hosted installation. GitHub documents this under "Permission levels for a personal account repository". While the repository belongs to a personal account, no customer is invited.

The check proves who submitted, not who wrote. For third-party code under a named person's name the customer answers under section 6 of the agreement.