Right to erasure (GDPR Art. 17)
Technical procedure to delete a visitor's data collected by the Korvus snippet, at the visitor's request, through your DPO team.
Context
Korvus acts as a processor within the meaning of Article 28 of the GDPR; you, as the site publisher, are the controller. When a visitor asks you to delete their data (GDPR Art. 17), you must be able to respond within one month at most (Art. 12).
This page describes the technical helper Korvus provides so you can carry out that deletion on the data collected through our snippet: raw_events, pageviews, sessions.
What is deleted
- The visitor's sessions for the website concerned
- The pageviews linked to those sessions
- The raw events (
raw_events) linked to those sessions
What is not deleted
The products and product_history tables only hold aggregated product metadata (SKU, observed price, availability), with no personal data and no visitor identifier. They are therefore not affected by an erasure request.
Alerts (alert_events) and baselines (baselines) are aggregated at site level, never at visitor level. The one exception: a video proof, when one exists, is attached to the session in which the incident occurred. It can only be accessed from that incident's case file, never by searching for a visitor, and it is purged along with the rest of the data.
Technical endpoint
POST https://app.korvus.fr/api/internal/data-subject-request
Authentication
Header Authorization: Bearer <INTERNAL_API_SECRET>. Your Korvus contact shares the secret with you out of band. Use it from a backend or a secure terminal, never in a browser.
Request body
Two mutually exclusive modes (one or the other, not both):
{
"website_id": "uuid-de-votre-site",
"session_id": "uuid-de-la-session-du-visiteur"
}
or:
{
"website_id": "uuid-de-votre-site",
"created_after": "2026-04-01T00:00:00Z"
}
| Field | Type | Required | Description |
|---|---|---|---|
website_id | UUID | Yes | Identifier of the site concerned |
session_id | UUID | Optional | Identifier of the visitor session to delete. It can be retrieved from your session export if the visitor provides it |
created_after | ISO 8601 | Optional | Date/time from which all of the website's sessions will be deleted (GDPR request window) |
Exactly one of the two fields session_id or created_after must be provided.
Response
{
"deleted": {
"sessions": 1,
"pageviews": 12,
"events": 84,
"dup_archive": 0,
"proofs": 2
},
"clickhouse": { "status": "ok" }
}
dup_archive covers session duplicates archived during deduplication, proofs covers video proofs (storage objects and metadata).
Check clickhouse.status. It is ok, skipped or failed. A failed comes back with an HTTP 200 code: the deletion did happen in the main database, but not in the analytics index. In that case, send the same request again: it is idempotent.
Error codes
| Code | Meaning |
|---|---|
401 | Missing or invalid secret |
400 | Invalid body (malformed UUID, neither session_id nor created_after provided) |
400 | created_after more than 30 days in the past (see the limit below) |
404 | Unknown website_id |
429 | Too many requests for this website_id. Respect the Retry-After header |
503 | Service temporarily unavailable. Try again; no data was touched |
500 | Server error. The deletion is cancelled (transactional ROLLBACK); contact support |
30-day limit on created_after
A single call cannot reach back more than 30 days: this limit protects the collection tables from an extended lock that would interrupt measurement for all of our customers.
To erase older history, chain several calls in 30-day windows, from the most recent to the oldest:
# Effacer 90 jours d'historique = 3 appels successifs
for OFFSET in 0 30 60; do
SINCE=$(date -u -d "$((OFFSET + 30)) days ago" +%Y-%m-%dT%H:%M:%SZ)
curl -X POST https://app.korvus.fr/api/internal/data-subject-request \
-H "Authorization: Bearer $KORVUS_INTERNAL_SECRET" \
-H "Content-Type: application/json" \
-d "{\"website_id\": \"$WEBSITE_ID\", \"created_after\": \"$SINCE\"}"
done
A single call over a window that is too wide returns a 400 without erasing anything: do not mistake it for a partial success.
curl example
curl -X POST https://app.korvus.fr/api/internal/data-subject-request \
-H "Authorization: Bearer $INTERNAL_API_SECRET" \
-H "Content-Type: application/json" \
-d '{
"website_id": "00000000-0000-0000-0000-000000000000",
"session_id": "11111111-1111-1111-1111-111111111111"
}'
Guarantees
- Transactional: deleting
raw_events+pageviews+sessions+ the deduplication archive runs in a single SQL transaction. If any step fails, everything is rolled back, leaving no partial state. - Scoped to the website: a DELETE can never touch another site's data, even through a configuration mistake. The
website_idfilter is present on every query. - Immediate on live systems: the data disappears without delay from our production databases (PostgreSQL and ClickHouse) and from video proof storage.
Backups
The data remains in our backups until they rotate out. Every backup system has this constraint. Here is exactly what it covers:
| Copy | Maximum retention |
|---|---|
| PostgreSQL full backups | 15 days |
| PostgreSQL hourly archives | 15 days |
| ClickHouse backups | 14 days |
| Native snapshots of the managed database | 7 days |
During this period, these backups are used for no purpose other than restoring the service after an incident. They are not consulted, analyzed or exploited.
Above all, every erasure is permanently logged. If we ever had to restore a backup taken before your request, our restore procedure requires a step that replays every recorded erasure before the service goes back online: erased data cannot reappear this way.
Once the rotation period above has passed, no copy remains.
Legal response time
The GDPR (Art. 12) requires you to respond to an erasure request within one month, extendable by two months for complex requests. The endpoint above lets you respond in a few seconds.