Docs

Security

No vanity claims — these are the practical controls in place today, and the ones teams should verify before sending production events.

Three credentials, three jobs

CredentialPrefixIngestReadWhere it lives
Secret keystl_sk_…yeseverything in the projectServer environment variables only
Public keystl_pk_…auto-capture batches onlynothingSafe in browsers and public repos
Feed token — one user, one account, or bothstl_ft_…noone actor's events & sessions, or one tenant's (account's) eventsBrowser, short-lived (60 s – 24 h)

Public keys are ingest-only. They can submit auto-capture events through POST /v1/events/batch and nothing else — any read attempt returns 403. That is a deliberate property: embedding a public key in a page can never expose other users' activity.

To show a user their own history in the browser, your server mints a feed token with the secret key (POST /v1/feed-tokens). The token is read-only and pinned to that one actor, to one of your customers' accounts (tenant_id), or both (and optionally one target); it cannot ingest, export, or read stats, and it expires. See the Feed Component guide.

Never expose secret keys in client-side code or public repositories. The dashboard itself never holds an API key in the browser — it uses its own session — so you can use it from any device.

Key lifecycle

  • Keys are shown once at creation and stored hashed — plaintext is never persisted.
  • Deleting a key revokes it instantly: the next request with it fails with 401.
  • To rotate, create a new key on the API Keys page, deploy it, then delete the old one. Feed tokens minted with the old key stay valid until they expire (at most 24 hours).
  • The integrity signing key (Ed25519) that signs checkpoints is Softechlog's, not yours: it lives only in the API's server environment. Its public half is published at GET /v1/integrity/keys; retired keys stay listed so old checkpoints keep verifying. Rotation and compromise handling are described in Tamper evidence · Keys.

Project isolation

Every event, actor, and session is scoped to a project at the database level. Each credential resolves to exactly one project and every query filters on that project ID — there is no cross-project read path. Within a project, feed tokens add a second boundary: each one is pinned to a single actor, a single account (tenant_id), or one user within an account, so a customer-facing feed can only ever show what that token was minted for.

CORS

Your customers' browsers legitimately talk to two things: the batch endpoint (with a public key) and the read endpoints (with a feed token). Those paths answer Access-Control-Allow-Origin: * without credentials — exactly as safe as the token they carry. Everything else (dashboard and account endpoints) is restricted to Softechlog's own origins.

Rate limiting

Redis-backed sliding window limits protect every public path:

  • 1,000 requests/min per secret key (ingest and feed-token minting)
  • 200 batch calls/min per public key (auto-capture batches events client-side to stay well under this)
  • 600 requests/min per credential on the query endpoints — a secret key, a feed token, or a dashboard session
  • 60 erasure requests/min per project, and at most 1,000 erasures in progress per project
  • 10 verify / bundle calls/min per project on the tamper-evidence endpoints, and 120/min per IP on the public /v1/integrity/keys
  • Per source IP on sign-in and sign-up (login codes, OAuth, the beta form)

Exceeding a limit returns 429 with a Retry-After header; the SDKs back off and retry automatically, and never surface it to your app. Retries are safe: every SDK event carries an Idempotency-Key, so a retried request never stores an event twice. The ingest and read limiters fail open: if Redis is unavailable, requests are still served rather than dropped. (Login and sign-up endpoints use fail-closed limiters so an outage can't strip brute-force protection.)

Tamper evidence

No API edits events. Every event is hashed when it is ingested (the response carries its leaf_hash), and every 5 minutes the hashes are sealed into hash-chained, Ed25519-signed checkpoints. The only ways data leaves are retention and per-user erasure — and verification explains both: deletions must fall behind a retention cutoff that is itself signed, or be covered by a sealed erasure record. Pin a checkpoint yourself and not even we can rewrite what came before it without detection. Read Tamper evidence for the exact encoding, the verifiers and the threat model.

Right to erasure

POST /v1/erasures (or erase() in the SDKs, or "Erase user…" in the dashboard) removes one user's personal data — their events, anonymous events in their sessions, their sessions and their actor record — and scrubs mentions of them as a target in other people's events. Erasure requests store a keyed hash of the user id, never the plaintext once they complete, and leave a sealed softechlog.actor.erased event in your log as evidence. See Erasure.

Transport & storage

  • All API traffic is TLS-encrypted in transit.
  • API keys are stored as hashes; feed tokens are signed and expire.
  • Auto-capture never reads form field values and strips query strings and fragments from URLs by default (see Auto-Capture · Privacy).
  • Retention is enforced automatically per plan (see Data Retention).

Your responsibilities

  • Keep secret keys in environment variables, not code — and only ever on the server.
  • Mint feed tokens only for the signed-in user (that's what the actor_id pins), with the shortest TTL that works for your page.
  • Don't put secrets, tokens, or raw PII you can't store into event metadata — it's stored as-is.
  • Use data-stl-ignore / data-stl-mask on sensitive UI so auto-capture never records it.
  • Pin checkpoints: store latestCheckpoint() daily somewhere you control and pass the pins to verifyIntegrity(). Without your own pin, tamper evidence rests on trusting us.
  • Put no personal data in erasure references — use a ticket id. The reference is stored and appears in the evidence event.

Evaluating Softechlog for a security-sensitive rollout? Schedule a technical call — we're happy to walk through the architecture.