Legal acceptance methodology
How Keypra OÜ records and preserves evidence that a user has accepted the current Terms of Service, Privacy Policy and related legal documents — and what we can produce on demand for a court, a Data Protection Authority or the user themselves.
Last updated: May 2026
1. Legal basis
Acceptance of Terms of Service is the formation of a contract under Article 6(1)(b) GDPR (necessary for the performance of a contract). Acceptance of the Privacy Policy is an acknowledgement of the controller's Article 13 information notice. Neither is a withdrawable Article 6(1)(a) consent — they are evidence of contract formation and notice. Optional telemetry and marketing flags are stored separately in the consent ledger.
2. What we capture at the moment of acceptance
- User ID — the immutable Supabase auth UUID.
- Document type & version — e.g.
terms_of_service / 2026-05-09. - Content SHA-256 — cryptographic hash binding the receipt to the exact published text.
- Timestamp — UTC, server-clock, set by Postgres on insert.
- Surface — where the click happened (
signup_email,signup_oauth_gate,re_consent,enterprise_invite_accept). - Verbatim checkbox label — the exact text the user saw next to the tickbox.
- Locale — browser language.
- IP address — captured from
x-forwarded-forserver-side, plus a salted SHA-256 hash so identification can be re-derived after the raw IP is purged. - Country code — derived from request headers.
- User agent — full
User-Agentstring. - Receipt ID — the row's UUID.
3. Tamper resistance
- The
legal_acceptancestable is append-only. Database triggers reject everyUPDATEandDELETE, including by service-role. - The
legal_document_versionstable is the single source of truth for the published text. Each row stores the immutable snapshot and its SHA-256 hash; the receipt references both via foreign key. - Row-Level Security: the data subject can read only their own receipts. Keypra staff with the
adminrole can read all receipts for legal-request fulfilment; nobody can write directly. - Inserts go exclusively through a server-side acceptance endpoint, which validates the session token, captures request headers, and writes one row per accepted document.
4. Retention
Receipts are kept for the lifetime of the contract plus the limitation period applicable in Estonia (Article 146 of the Estonian Law of Obligations Act — 3 years for general claims, 10 years for written agreements). Raw IP addresses are blanked 13 months after acceptance via a pg_cron job; the salted IP hash and all other fields remain, preserving the evidentiary chain while honouring data minimisation under Article 5(1)(c) GDPR.
5. Re-consent on policy change
When we publish a new version of the Terms or Privacy Policy, the LegalGatemiddleware redirects every signed-in user to /welcome/accept-terms on next navigation. The legal_acceptance_status RPC compares the user's most recent receipt against the latest published version per document and reportsneeds_acceptance: true when a new acceptance is required.
6. Producing evidence on demand
For each user/document, Keypra OÜ can produce a single PDF evidence pack containing every field listed in §2, alongside the archived snapshot of the accepted text. Users can download their own pack at any time fromSettings → Privacy → Legal acceptance history. A court order, DPA request or GDPR Article 15 subject access request can be served onlegal@keypra.com.
7. Standards we align with
- GDPR Article 7(1) — burden of proof of consent on the controller.
- EDPB Guidelines 05/2020 on consent — recording and demonstrability.
- eIDAS Regulation (EU) 910/2014 — admissibility of electronic records as evidence.
- Estonian Personal Data Protection Act (IKS) — local enforcement standard.
8. Withdrawal waiver (consumers, EU)
EU consumers have a 14-day right of withdrawal from digital-service purchases under Directive 2011/83/EU and its Polish implementation. Article 16(m) allows that right to be waived only where the consumer has given express prior consent to immediate performance and acknowledged the loss of the withdrawal right. Keypra collects this consent as a separate, explicit checkbox at every paid checkout entry point — never bundled with acceptance of the Terms or Privacy Policy.
- Surfaces. Shown at
checkout_subscription,checkout_topup,checkout_capacity_boostandcheckout_lecturer_license. Stripe Checkout is not opened until the consent row has been written. - Audience filter. Skipped for business buyers (
entity_type === 'company') — the statutory right applies only to natural persons acting outside their trade or profession — and for users in regions blocked from self-service paid checkout. - Evidence row. Recorded in
legal_acceptanceswithdocument_type='withdrawal_waiver', version labelv2026-05, the verbatim waiver text, and whitelistedmetadata(product key,buying_as, and the Stripe session ID when available). - Failure mode. If the consent row cannot be written, Stripe Checkout is not opened. There is no silent-fail path that activates a paid Service without a recorded waiver.
- Confirmation. The purchase confirmation email re-states the waiver text and the right being waived, satisfying Article 8(7) of the Directive.
- Contestability. Consumers may dispute the waiver or request a refund at billing@keypra.com. Statutory consumer rights under the country of residence remain unaffected.