Skip to main content

Data retention

A KYC provider is pulled in two directions at once. AML rules require keeping the evidence of an identity check for years. Data-protection principles require not keeping biometric data a day longer than there is a basis for.

The only way to satisfy both is to delete on a schedule. This page describes that schedule, what it removes, and — just as important — what it deliberately does not.

These periods are a policy, not legal advice

The periods below were set by the business and implemented in code. They do not establish your obligation. The exact requirement varies by the regulated activity of your organisation, not only by country. Confirm with legal counsel before relying on them.

The periods

JurisdictionImages kept for
Paraguay5 years
Rest of LatAm8 years
Unknown8 years

Measured from submitted_at — the moment the verification was submitted, not the moment it completed.

Why "unknown" gets the longest period, not the shortest

This is the part most people expect to be the other way round, so it is worth explaining rather than just stating.

The two errors are not symmetric:

  • Deleting too early destroys evidence you are legally required to hold. It is unrecoverable. Nothing fails visibly at the time; you find out during an audit, when the record is asked for and is not there.
  • Keeping too long is a cost and a data-protection question. It is correctable tomorrow.

So every case where the jurisdiction is not certain gets the longest period.

That is not theoretical caution. Nationality comes from OCR of the document, and on real traffic 9 of 21 verifications carried no nationality at all, while one read PYG — the Paraguayan currency code, which the model had mistaken for a nationality. A policy keyed on that field without a safe default would have silently deleted real records three years early.

For the same reason, several spellings map to the Paraguayan period rather than only the ISO alpha-2 code: PY, PRY, PYG, PARAGUAY, PARAGUAYA, PARAGUAYO. Anything else — including an empty field — takes the 8-year default.

The floor

The two periods are readable from the environment (VERIDIA_RETENTION_DAYS_PY, VERIDIA_RETENTION_DAYS_DEFAULT), but a hard floor of 5 years is applied after the environment is read. No configuration value, however mistaken, can cause anything younger than that to be deleted. A typo in a deployment variable cannot wipe live evidence.

The floor raises; it never lowers. Setting a period longer than 8 years works. Setting one shorter than 5 years has no effect.

What is deleted, and what is not

The sweep deletes only the image objects: the document front, the document back, and the selfie.

The database row survives. That is deliberate — the row is the record of the identity check, and destroying it would defeat the purpose of retaining anything. What survives, indefinitely, is:

CategoryFields
Identityextracted_name, extracted_document_number, extracted_date_of_birth, extracted_nationality, extracted_document_type
Outcomestatus, verdict, confidence, scores, flags, breakdown, errors
Linkageid, tenant_id, user_ref
Audit trailsubmitted_at, completed_at, images_deleted_at, reviewed_by, reviewed_at, review_note
Request contextclient_ip, user_agent, latency_ms
Two honest gaps in that table

client_ip and user_agent are personal data and are not part of the identity-check record that retention is meant to preserve. They are kept indefinitely today because nothing purges or anonymises them. There is no mechanism to remove them.

The webhook delivery outbox stores each event's full payload, including fieldsExtracted (name, document number, date of birth). Those rows are not touched by the retention sweep either. If you are building an inventory of where identity data lives, include both.

How the sweep runs

A systemd timer on the backend host runs the sweeper once a day.

Schedule04:30 server local time (currently America/Argentina/Buenos_Aires, UTC−3)
JitterUp to 10 minutes after the scheduled time
Missed runsRecovered on next boot (Persistent=true) — a reboot does not skip a day
Batch cap200 verifications per run

The sweep works in two stages, on purpose. A SQL filter selects candidates using the shortest configured period, so nothing eligible is ever missed; the per-jurisdiction decision is then made in application code, where the policy is written once and can be tested.

For each expired verification it deletes the image objects, then:

The row is marked as deleted only if every object was actually removed. If a single delete fails, the mark is left unset and the next day's sweep retries.

This matters more than it looks. The alternative — marking the row regardless — produces a database that certifies a destruction that did not happen, while the file is still sitting in storage. A false record of deletion is worse than no deletion, because it cannot be detected by looking at the database.

Current state

No verification in the system is yet old enough to expire, so the sweep has not deleted anything to date. It runs daily, in deleting mode, reporting zero eligible rows. It was enabled now rather than years from now on the reasoning that a control someone has to remember to switch on later is not a plan.

Deletion on request

There is no implemented mechanism for deleting a specific person's data on request. No API endpoint, no dashboard control, no self-service path.

A request of that kind today means a manual database and storage operation performed by an operator. If your obligations include honouring erasure requests within a fixed window, factor that in: see GDPR for what does and does not exist.

Note also that erasure and AML retention pull against each other. Deleting a record you are legally required to retain creates a different problem from keeping it. Which one binds you is a legal question, not a technical one.

Your own retention

Retention on Veridia's side says nothing about the copies you hold.

Every webhook you receive contains identity PII. If you store the payload, log the request body, or forward it to an analytics or error-tracking service, those copies are yours to inventory and expire. The same applies to any verdict you cache from GET /v1/verify/{id}.