Skip to main content

Accounts, tiers and billing

Getting an account

Registration is at /register. While BETA_SIGNUP_CODE is set, a matching code is required and requests without one are refused — which is why an open beta can be closed without a deploy.

Existing users can bring others in directly: an invite creates a signed, single-use link (/invite/{token}) that lands the recipient on a pre-filled registration form. Password reset works the same way, through /password-reset-request and a /password-reset/{token} link.

Once signed in you have two credentials, and they are not interchangeable:

  • a session cookie for the web pages, and
  • one or more API keys for the mobile app, the desktop client and anything you write yourself. Generate these from your profile page.

See the introduction for how the two differ in practice, including why a missing key returns 422 and a bad key returns 401.

Your profile and garage

Your profile carries your display name, avatar and riding styles. The garage is your list of motorcycles, drawn from a vehicle catalogue the platform maintains:

Search the catalogueGET /vehicles/search
Browse by manufacturerGET /vehicles/makes, GET /vehicles/models
One modelGET /vehicles/models/{model_id}
Its OBD-II parametersGET /vehicles/models/{model_id}/obd
Report a correctionPOST /vehicles/models/{model_id}/obd/report
Where the data came fromGET /vehicles/sources

The OBD endpoints back the app's dongle support: knowing which parameters a given model exposes is what makes a live reading meaningful.

Performances

Rides can be scored against each other. POST /performances records an effort, GET /performances lists yours, and GET /performances/leaderboard ranks them. DELETE /performances/{effort_id} removes one.

Tiers

Plans are subtractive from the top: the app ships complete, the highest tier holds every feature by construction, and lower tiers are what remains after subtraction (app/services/features.py). The ladder is:

PlanPosition
FreeEvery signed-in user, including lapsed subscribers
TrialFourteen days with the Pegasus claim set
CentaurEntry paid tier
PegasusMiddle tier
AlicornEverything

Each feature declares the lowest plan that includes it, so moving a feature between tiers is a one-value change rather than a scattered edit. Two kinds of feature are enforced differently, and the difference is deliberate:

  • Server features gate an API route. A request without the claim is refused.
  • Client features shape the app's own interface. They cost nothing at the margin, so they are enforced softly and circumvention is accepted rather than fought.

Per-plan grants can also be flipped at runtime without a deploy, through GET /billing/admin/features and PUT /billing/admin/features/{plan}/{slug}.

Billing

What you are entitled toGET /billing/me
Start a subscriptionPOST /billing/checkout
Stripe callbacksPOST /billing/stripe/webhook

GET /billing/me returns the claims payload the clients read to decide what to show. Checkout uses the price named by STRIPE_PRICE_ID, or the per-tier mapping in STRIPE_PRICE_MAP. Webhooks are signature-verified with STRIPE_WEBHOOK_SECRET, which is why that endpoint needs no API key.

:::tip Billing can be switched off entirely While BILLING_ENABLED is unset, every entitlement check passes. A deployment can run the full feature set without a payment provider configured, which is what a self-hosted or pre-launch instance does. :::