dispatch
Sessions waiting on you:0finished:0· all quiet
Sign inGet early access

Legal Data

Privacy Policy

Every field the app sends, every row the server keeps, why the hardware id exists, how long an events row lives, and what actually happens when a deletion request arrives while a subscription is live.

Updated

This is written from the database schema rather than from a template. Every field named below is a real column, and the list is exhaustive — if something is not on this page, the server does not have it.

The controller is TODOthe registered legal name — set LEGAL.owner.legalName in src/lib/site.ts, whose full identity is on Trader identity.

The part most people want first

Dispatch is a terminal. What you run in it never leaves your machine. No command, no output, no file path, no project name, no prompt you sent an agent, and no reply it sent back. There is no telemetry, no crash reporter, no analytics SDK and no usage tracking in the application at all.

What does leave your machine is the licence check, and it is five fields.

What the app sends, at every launch

Field Example Why it is sent
key {LICENCE.keyFormat} To ask whether this licence is currently valid.
fingerprint m_9f2c… To count how many machines the key is on. See below.
machine.name WIL-DESKTOP So the seat list reads “which of these three is my laptop” rather than three hashes. It is your computer’s hostname.
machine.os win32 10.0.26200 Support, and so the seat list is legible.
appVersion {SITE.version} To tell a bug in an old build from a bug in the server.

That is the whole request body. There is no sixth field, and there is no second endpoint that sends anything else.

The hardware id, exactly

The fingerprint is not your machine’s hardware id. It is:

'm_' + sha256(platform + '|' + arch + '|' + machineGuid).slice(0, 32)

On Windows machineGuid is the MachineGuid value Windows generates at install time, with the equivalent on macOS and Linux. The raw value never leaves your computer — it is hashed first, and only the first 32 hex characters of the digest are sent.

What that identifier is used for, completely:

  • Counting to 3, so a key cannot be shared across a team.
  • Matching a machine you are releasing from the activation screen.
  • Making sure a trial is issued once per machine as well as once per address.

What it is not used for: nothing else. It is not joined to any advertising identifier, not shared with a sub-processor, not sold, not used to build a profile, and not compared against anything outside our own machines and trials tables. It is deliberately not a MAC address, so it does not change when a VPN comes up and does not identify your network.

We chose a hash rather than the raw value for one reason worth stating: it means a copy of our database does not hand anyone a list of Windows machine GUIDs.

What the server stores

Four tables. This is all of them.

Licences

Email address, licence key, plan, whether it is a trial, status, expiry date, machine allowance, an internal note, the Stripe customer and subscription ids, and created and updated timestamps.

Purpose: to know whether you have paid and what you are entitled to. Lawful basis: performance of a contract with you.

The Stripe ids are references, not payment data. No card number, expiry, CVC, billing address or bank detail ever reaches us — Stripe’s hosted checkout takes those directly. That is not a security promise we are asking you to trust; it is an architectural fact, and it is why this page has nothing to say about how we protect your card.

Machines

For each seat: the fingerprint above, the machine name, the operating system string, the app version, and when it was first and last seen.

Purpose: to enforce the 3-machine limit and to let you release a seat yourself. Lawful basis: performance of a contract.

last_seen is also the only usage signal that exists anywhere. It records that a licence checked in, not what you did.

Trials

Email address, fingerprint, the licence it produced, and when.

Purpose: to make sure one free trial goes to one person and one machine. Lawful basis: our legitimate interest in preventing repeated free use of a paid product.

This row outlives the licence. It is kept even after the licence it created is deleted, because deleting it reopens an unlimited supply of free trials to anybody who asks. It holds an address and a hash and nothing else. It is the one piece of data on this page that survives an erasure request, and the section on deletion below says so plainly rather than leaving you to discover it.

Events

An append-only log: trial_started, machine_added, machine_released, purchased, trial_converted, renewed, subscription_*, minted, extended, revoked, restored. Each row has a type, a timestamp, and a small JSON payload — which for some types contains the email address and the fingerprint.

Purpose: to answer “what happened to this licence” when you write in, and to make fraud visible. Lawful basis: our legitimate interest in supporting and defending the service. We think that is proportionate because the log records licence lifecycle only, and because without it the honest answer to a support question would be a guess.

An events row is kept for 24 months from its timestamp, then deleted. Rows belonging to a deleted licence are removed at the same time as the licence — see below, because the database does not do that part on its own.

Accounts — how you sign in to this site

One row per email address, created the first time you sign in. It holds the address, the times it was created and last changed, and a password hash, only if you chose to set one.

Signing in normally needs no password at all: you enter your address and the server emails a single-use link. A password is an opt-in convenience you can add — or remove again — from your account page. There is no “forgot password” flow, because proving you control the address is already how you sign in, so the emailed link is the reset.

Purpose: to let you see your licence key, the machines using its seats, and your billing, without emailing us. Lawful basis: performance of the contract — this is the account you bought.

Three specifics about the password, because “we hash passwords” is what everybody says:

  • It is stored as scrypt (N=16384, r=8, p=1) with a per-password random salt, never in plain text and never recoverably. We cannot tell you what your password is.
  • We cannot tell whether an address has an account. The sign-in form answers identically for a wrong password, an address that never set one, and an address with no account. That is deliberate: the list of addresses that bought a developer tool is worth enumerating, and a form that distinguishes those cases hands it over.
  • Setting or changing a password deletes every other session for that address.

Kept until you delete the account, and removed with it. Removing just the password leaves the row and clears the hash.

Both are short-lived rows, and neither stores the credential itself: only a SHA-256 of the token is kept, so these tables are not a set of working keys if they leak. A sign-in link is single-use and valid for 15 minutes; a session lasts 30 days or until you sign out.

Each row holds the email address, the timestamps, and for a session the time it was last used. Spent links and expired sessions are deleted automatically — this is the one retention job that is not run by hand.

Lawful basis: performance of the contract. Without a session there is no account area.

Your IP address

Used, and not stored. Every request is counted against a rate-limit bucket keyed on the route and the calling address. Those buckets live in memory, are swept as they expire, and are gone when the server restarts. No IP address is ever written to the database.

Wrong-password attempts are counted per address as well as per IP, in the same in-memory buckets — five in fifteen minutes and that address stops accepting password attempts for the rest of the window. The emailed link still works, so a lockout is never a lockout. Nothing about those counters is written to the database either.

Our hosting provider’s own request logs are a separate thing and do contain addresses — that is Railway’s retention, listed on Sub-processors.

This website

Separate from the app, and much smaller.

  • No analytics. No page-view counting, no heatmaps, no session recording, no pixels.
  • No third-party requests. Fonts are self-hosted; the pages you are reading load nothing from anyone else’s server.
  • Two cookies, both strictly necessary, both only after you sign in. Nothing else on this site sets one, and if you never sign in there are none at all. Named, with their flags and lifetimes: Cookies.
  • Signing in is passwordless. You give an email address, the licence server emails a link, and following it exchanges a one-time token for a session. There is no password, so there is no password hash to protect, no reset flow, and nothing of that kind to lose in a breach. The address is one we already have — it is the one your key was issued to.
  • The account area reads, it does not collect. It shows you the licence, machines and subscription described above. It creates no new record about you beyond the session.
  • The waitlist stores the address you give it, uses it to send exactly one email when the trial opens, and is consented to by submitting the form.

Who else touches it

Four sub-processors, each named with what it receives and why, on Sub-processors: Stripe (payments), Resend (sending you your key), Railway (hosting and the database), GitHub (release downloads and updates).

All four are in the United States. Transfers rely on each provider’s own Standard Contractual Clauses and its Data Privacy Framework certification where it holds one; the sub-processors page links to each agreement so you can check rather than take our word.

We do not sell personal data, share it for advertising, or use it for automated decision-making or profiling.

How long things are kept

What How long
Licence and machines, active subscription For as long as the subscription runs.
Licence and machines, after it lapses 24 months, so a returning customer keeps the same key — then deleted.
Events 24 months from the row’s timestamp.
Trials Indefinitely, for the reason given above. Address and hash only.
Account row, including any password hash Until you delete the account.
Sign-in links 15 minutes, or until used. Deleted automatically.
Sessions 30 days, or until you sign out. Deleted automatically.
Waitlist address Until the trial opens and the one email is sent, or until you ask, whichever is first.
Stripe records Stripe’s own retention, driven by financial and anti-fraud rules we cannot shorten.

Honest caveat. Most of these periods are enforced by hand, not by a scheduled job — nothing in the licence server prunes licences or events on a timer yet. If a retention period matters to you, ask and we will run the deletion while you wait rather than telling you to trust a cron that does not exist.

The two exceptions are the last two rows above: expired sessions and spent sign-in links are deleted automatically, swept on each successful sign-in rather than by a timer. Those are credentials, and a credential outliving its window is a different class of problem from a stale record.

Your rights

If you are in the UK or the EU you have the right to access your data, to get a copy in a portable form, to correct it, to have it deleted, to restrict or object to processing based on legitimate interests, and to complain to a regulator. Similar rights exist in other places; we apply them to everybody rather than checking where you live first.

To use any of them, write to us:

TODOthe privacy address — set LEGAL.contact.privacy in src/lib/site.ts

We answer within 30 days and usually within a few days. There is no charge, and we will not ask you for identity documents — you write from the address the licence was issued to, which is the same proof the software itself uses.

To complain to a regulator:

TODOthe supervisory authority for the business's jurisdiction — set LEGAL.owner.supervisoryAuthority in src/lib/site.ts

Deleting your data while a subscription is live

This is the part most policies skip, so here it is in full.

Deleting your licence is the same act as ending your access. The licence row is the entitlement. Erase it and the next launch check fails — not at the end of the period you paid for, but immediately, on every machine, worldwide, including the one you are working on. There is no version of “delete my data but leave the software running”, because the data is what makes the software run.

So when a deletion request arrives while a subscription is active, this happens:

  1. We write back once, to confirm you understand that access ends at once rather than at the period end, and to ask whether you would rather cancel now and have us delete everything when the period runs out. Either answer is fine. That message is the only thing standing between the request and the deletion — it is a confirmation, not a retention attempt, and we will not ask twice.
  2. We cancel the subscription in Stripe at the same time, so a deletion never leaves a live charge attached to an account that no longer exists.
  3. We delete the licence row. The machines attached to it go with it automatically — that cascade is enforced by the database.
  4. We delete the events rows by hand. The database does not cascade those, and some of them contain your address and your fingerprint. Leaving them would make the deletion a lie, so removing them is part of the procedure rather than an afterthought.
  5. We delete the account row, any password hash, and every session, by hand. These are keyed on your email address rather than on the licence, so the database does not cascade them either. Same reasoning as the step above: an account row surviving a deletion request would mean the address is still on the server after we said it was not.
  6. The trials row stays, holding your address and the machine hash. This is the one exception, it is retained under legitimate interests to stop the free trial being re-issued, and you can object to it — in which case we weigh your objection properly rather than reciting the interest back at you.
  7. Stripe keeps its own record of the transaction for as long as financial and anti-fraud rules require. We cannot delete that and neither can they. It is a payment record, not a profile.

If you would rather not lose access, cancel instead of deleting. You keep the software until the end of the period you paid for, and everything is deleted 24 months later on the schedule above — or sooner if you ask again then.

Children

Dispatch is a developer tool sold to adults. It is not directed at children, and we do not knowingly collect data from anyone under 16. If you think we have, write to the privacy address and it will be deleted.

Security

The parts worth stating because they are structural rather than aspirational:

  • The database is reached over Railway’s private network, and certificate verification is never disabled in production.
  • Entitlements are signed with Ed25519. The private key exists only in the server’s environment and has never been in a repository.
  • Admin endpoints require a bearer token compared in constant time, and the server refuses to start without one.
  • Stripe webhooks are verified against the raw bytes, with a timestamp window, so a captured webhook cannot be replayed.
  • Card data never reaches us at all.

How to report a hole in any of that: Security and disclosure.

Changes to this policy

The date at the top changes when the text does. If a change materially affects you — a new sub-processor, a new field collected, a longer retention period — we email the address on your licence before it takes effect rather than relying on you to re-read the page.