Privacy & compliance
Retention, erasure, and AI disclosure.
The platform handles photographs of real people. Three commitments follow from that.
Read the status markers. This page describes the Try-On API, parts of which are specified and not yet built. Anything marked Not built yet is a design you can rely on us not to change, not a call you can make today. The binding statement of what we actually do with a photograph is the Privacy Policy.
Retention
Shopper photos are deleted automatically after 1, 3 or 7 days — set per account. Within that window a returning shopper reuses their photo instead of re-uploading.
Shorter retention is the privacy-conservative choice; longer is the smoother repeat experience.
Deletion is an hourly sweep that removes the stored object first and marks the row afterwards, so nothing is ever recorded as deleted while the bytes are still there. Objects are stored with caching disabled — at a one-hour cache a link signed before deletion kept serving the photo from a CDN edge for an hour after the purge.
Not built yet: a per-request output.keepForDays override. The pipeline carries a retention value per generation, but no public endpoint exposes it, so the account setting is the only control today.
Never used for training
Shopper photographs are never used to train models. Say so in your widget, on your site, and in your DPA — it is the single most common shopper objection.
Right to erasure
Built 2026-09-13. This section previously said the call below did not exist and never had — it was written from the specification and published as though it had shipped. It exists now, and this is that correction being retired. If you built against it before 2026-09-13, nothing was deleted; run it again.
Tag a shopper by sending externalUserId on the try-on — your own customer id, the one you can match to a person who emails you. Then:
curl -X DELETE "https://www.genfashion.app/api/tryon/v1/customers/user_42" -H "x-api-key: sk_your_secret_key"{
"customerId": "user_42",
"erased": true,
"personImagesDeleted": 1,
"generationsAnonymised": 3,
"objectsRemoved": 4,
"erasedAt": "2026-09-13T09:41:02.113Z"
}GET the same path first to see what is held — counts, first and last seen, and the consent trail. A right to erasure is not much use without a way to know there was something to erase, and the response is something you can file against the request.
What is removed: the photograph, the result image made from it, and every identifier and consent record tying a generation to that person. What stays: that a generation happened, what it cost and which model ran, as an anonymous row. A subject request is not a licence to erase your own billing history, and the row can no longer be connected to anybody.
Bytes go before records. If storage cannot be reached the call returns 503 and changes nothing — it will not report an erasure it did not perform.
From the storefront widget. The same applies without the server API: mint the session with your own customer id —
POST /api/storefront/v1/sessions { "shopperId": "user_42" }— and every try-on in that session is tagged with it. Erasure matches either identifier, so user_42 is found whether it arrived as a shopperId on the storefront or an externalUserId through the server API. Which one a request reaches you by depends on where the shopper came from, and the person asking does not know the difference.
Untagged try-ons. A shopper who passed neither is matched on the widget's own generated per-browser reference, which the admin can search under Privacy. That reference does not survive a cleared cookie, so it cannot always be produced for someone who asks by email — which is the whole reason to send an id you control. Photographs still expire on the retention window above either way.
EU AI Act
Built 2026-09-13. This page previously described the disclosure as though it shipped, then carried a correction saying it did not. Both are now retired. Every result carries:
- A visible AI MODIFIED badge, composited bottom-right, per the European Commission's disclosure guidance.
- Machine-readable provenance in the image's own metadata —
Software,Digital Source Type: trainedAlgorithmicMedia(the IPTC term for media produced by a generative model), and a comment naming the model and the generation id.
The badge can be turned off for an account in Settings → Workspace, or per call with output.aiLabel: false on the server API. The metadata cannot be turned off — there is no setting for it here or anywhere, because an option to omit a machine-readable "this is synthetic" marker would make the mechanism worthless to exactly the people who rely on it.
The widget API does not accept the override at all. It is driven by a publishable key that ships in your page source, so anyone who read it could otherwise strip the disclosure.
What this is not
It is not C2PA. C2PA is a signed manifest — a cryptographic claim bound to a certificate that a verifier can trace to an issuer. What is written here is an unsigned PNG text chunk: anyone can strip or forge it. It is the honest, cheap version, and it is enough for a downstream tool reading metadata in good faith and worth nothing against anyone acting in bad faith. Signed C2PA is still unbuilt and still on our list. This section exists so nobody reads "provenance metadata" and assumes more than is there — which is the mistake the retraction above was written for.
Before 2026-09-13
ai_label_applied and watermark_applied defaulted to true from the first migration, so every row created before 2026-09-12 asserted a label that had never been composited onto anything. Migration 0048 corrected all of them to false. Treat any result generated before 2026-09-13 as unlabelled, whatever an old record says — the column is now set from what the compositor actually did, and only from then.
