Documentation
Sentry handles licensing, authentication, software delivery, and user management for desktop applications. This guide covers the APIs, the signed authentication response, and the SDKs.
Introduction
Applications authenticate against the public API with an app key plus either a license key or user credentials. Each application has its own Ed25519 key pair. Responses are signed with the private key and verified in your client against the embedded public key, so a client can tell a real response from a forged one.
Licenses, builds, users, bans and webhooks are managed from the dashboard or the management API.
The platform includes:
- Tenant dashboard
- Public client API: what your shipped software calls
- Management API: server-to-server automation
- Webhooks
- C/C++ and C#/.NET SDKs
- Ed25519-signed authentication responses
Quickstart
These steps use the hosted API. There is nothing to install.
1. Create an app
Sign in to the dashboard and create an app. It gets an Ed25519 key pair. Copy its app_key and pubkey_hex. The public key ships in your client.
2. Mint a license key
Create keys with seats, an expiry and tags, one at a time or in bulk from a template.
3. Authenticate a key
curl -s https://api.sentry.example/api/v1/auth \ -H 'content-type: application/json' \ -d '{"app_key":"app_...","key":"KEY-XXXX-YYYY","hwid":"machine-id","nonce":"a1b2"}'
4. Verify the response
Call auth from an SDK. It checks sig against the public key before reading any field, so you don't touch the signature yourself.
sd from the JSON fields. Verify the exact bytes the server returned, then read the fields out of them.Architecture
There are three APIs, each with its own authentication method:
| API | Path | Auth | Called by |
|---|---|---|---|
| Public client | /api/v1/* | app_key + license or user credentials | your shipped software |
| Dashboard | /account/*, /dashboard/api/* | session cookie | the tenant dashboard |
| Management | /api/v1/manage/* | Authorization: Bearer | your backend / automation |
The app key identifies the application on every public call. Application-scoped queries are constrained by the owning tenant, so one tenant can't read or modify another's data.
Authentication flow
Authentication response
A successful authentication returns two fields:
| Field | Description |
|---|---|
sd | The signed payload: key=value pairs joined with |. |
sig | Ed25519 signature over the bytes of sd, base64-encoded. |
v=1|ts=..|nonce=..|hwid=..|ok=1|username=..|name=..|expires=..|latest_version=..
Verify in this order and stop on the first failure:
| Check | Why |
|---|---|
Verify sig over the exact bytes of sd | Proves the response came from the app's private key, not a spoofed or proxied server. |
Check ok=1 | The request was allowed. |
Check nonce matches the one you sent | Confirms the response belongs to this request and blocks replayed responses. |
Check hwid matches this machine | Confirms the response was issued for this device. |
Check ts is recent | Rejects a stale response captured from an earlier session. |
Read name, expires and latest_version only after every check passes.
Developer notes
sdis UTF-8 and uses|as the field delimiter.- Field order is fixed. A new field bumps the
v=version; verify against the version you built against. - Ignore fields you don't recognize.
- Reject a
tsolder than five minutes. - Verify the signature before parsing anything out of
sd.
Public client API
Base path /api/v1. Select the app with app_key (JSON body on POST, query string on GET). Signed endpoints require a hwid and accept an optional nonce.
| Endpoint | Body | Purpose |
|---|---|---|
POST /auth | key, hwid, nonce? | Validate a bare license key. Signed response. |
POST /register | username, password, key, hwid | Create an account by redeeming a key. |
POST /login | username, password, hwid | Authenticate an existing account. |
POST /file/latest | key or username,password | Download the latest build; hash + signature verified. |
POST /poll | session | Long-poll control channel (protocol v2). |
GET /pubkey | query | The app's ed25519 public key (bootstrapping). |
GET /version | query | The advertised latest version. |
Seat enforcement is automatic: a key admits an hwid that is already a device, or while the key has fewer active devices than its seats; otherwise it is denied with seat_limit_reached.
Sessions & long-poll (protocol v2)
Send proto: 2 on auth. The response then includes a session token, and the client can hold a control channel with POST /poll: the server holds the request up to ~25 seconds and returns as soon as a directive is queued for that session, otherwise it returns idle.
| Directive | Meaning |
|---|---|
revoked | Session or device revoked. Stop the client. |
kill | App paused (kill switch). Stop the client. |
update_required | Client is below the enforced minimum version. |
idle | Window elapsed with nothing queued. Reconnect. |
A client that doesn't send proto:2 gets the v=1 response unchanged.
REST admin API
Base path /api/v1/manage, authenticated with Authorization: Bearer <token>. Create tokens in the dashboard with per-resource scopes and an optional expiry. An empty scope set means full access.
curl -X POST https://your-host/api/v1/manage/apps/$APP_ID/keys \ -H 'authorization: Bearer sk_live_...' \ -H 'content-type: application/json' \ -d '{"count":1,"expires_days":365}'
Scopes are drawn from keys, users, files and bans, each :read or :write. A route rejects an out-of-scope token with insufficient_scope; expired tokens are rejected at auth.
Webhooks
Register HTTPS endpoints to receive events (auth.success, auth.fail, ban.hit, and more). Deliveries are signed with a per-webhook secret. Targets are validated against SSRF at creation and at delivery. Private, loopback, link-local and metadata addresses are blocked.
SDKs
The SDKs do the verification, manage the session, and handle the long-poll directives. Available for C/C++ and C#/.NET.
C# / .NET
using Sentry; using var client = new SentryClient(baseUrl, appKey, publicKeyHex, useProtocolV2: true, device: new SentryDeviceInfo { Version = "1.4.66", Os = "Windows 11" }); var r = await client.AuthAsync("KEY-XXXX-YYYY"); if (!r.Ok) return; // r.Reason explains why // live control channel (revoke / kill / update) await client.StartPollingAsync(evt => { if (evt.Directive == SentryDirective.Revoked) Environment.Exit(0); }, ct);
C / C++
#include "sentry_auth.h" sentry_config cfg = {0}; cfg.base_url = base_url; cfg.app_key = app_key; cfg.pubkey_hex = pub_hex; cfg.use_proto2 = 1; sentry_client *c = sentry_client_new(&cfg, NULL); sentry_auth_result r; if (sentry_auth(c, "KEY-XXXX-YYYY", &r) == SENTRY_OK) { /* r.name / r.expires are verified and safe to trust */ }
Each SDK ships with a README covering the full API, the build and link setup, and the long-poll loop.
Enterprise & on-prem
The hosted service needs no infrastructure on your side. Self-managed and on-premise deployments are available on the Enterprise plan for compliance, data-residency, or air-gapped environments.
Enterprise also adds SSO, audit-log exports, an SLA, and priority support. App signing keys are encrypted at rest and never leave your tenant.
Security posture
How the platform protects tenants and clients:
- Signed-string field injection: values reflected into
sdare allowlisted at input and stripped of delimiters. - One key, one account: redemption is an atomic conditional update backed by a uniqueness constraint.
- HWID / seat locks: enforced on every auth path.
- Webhook SSRF: private/loopback/metadata targets blocked at creation and delivery.
- CSRF: Origin/Referer checked on cookie-authenticated mutations, with SameSite cookies.
- Encrypted key vault: per-app private seeds are AES-256-GCM encrypted; only public keys are exposed.
- Role-gated dashboard: read-only members can view but not mutate; team/token/audit routes require admin.