# Data protection and your responsibilities

> Part of the Cowliss docs. Markdown for every page: append `index.md` to its URL. Site map: /llms.txt

Every Cowliss organization is the **controller** of its own data: you decide what your users' data is for, you establish the lawful basis (GDPR Art. 6), and you answer to your users. Cowliss is the **processor** (Art. 28): it stores and moves personal data only on your documented instructions. The contract layer lives under [Legal](/legal/dpa/); this page is the practical half: the defaults you accept by using Cowliss, and the tooling you get for data rights.

Each default below is a **documented instruction**: it reads as something you instruct Cowliss to do, not a policy Cowliss imposes on you.

## Default 1: ingestion is unconditional, consent gates sends

Cowliss ingests every event you send it, **regardless of the profile's consent state**. Consent is enforced at the moment of action: every send checks the consent map before an email whose purpose a recipient can withhold, or a marketing automation's webhook, goes out and records `skipped_consent` in the delivery log when the purpose is off.

The split is deliberate. Storing what your apps observed is a different act from contacting the person, and gating at send time means a consent change takes effect everywhere at once, including for automations already in flight. If your lawful basis requires not storing someone's events at all, don't send them.

One carve-out, also part of this default: templates that declare bare **`transactional`** (a receipt, a password reset) bypass consent by design, because a receipt must not vanish just because someone once left a newsletter. They still stop on suppression, quota, and a sending pause.

## Default 2: a purpose is why you are contacting someone

Every email declares a **purpose** on its template, and it answers one question: why this message goes out. A purpose is a path under one of two roots:

- **`marketing.<name>`**, such as `marketing.newsletter`: off until you record a yes.
- **`transactional.<name>`**, such as `transactional.weeklyReport`: mail about the person's own account that they may still want to stop. On until they turn it off.
- **`transactional`**, bare: a receipt, a password reset, a verification link, a security notice. It must reach the person whatever they chose, so nobody can withhold it.

The names are yours. You declare each one in `cow.json` with the label a recipient reads, and it belongs to that app alone: a profile belongs to one app, so it answers only its own app's purposes, and two apps may declare the same path and mean different things. What a name *means* is controller-defined, so publish that meaning to your recipients. Cowliss never interprets it; it only honors the answers.

A send under a name needs the name and its root both on. Granting a name turns its root on, so one key is a complete signup. Turning a root off turns off every name under it. Bare `transactional` is never asked: the `transactional` root turns off only the names under it, never bare mail such as a receipt, while everything that protects the address itself (suppression, your credit, a sending pause) still applies.

A new profile starts with every `marketing` purpose off: being ingested is not agreeing to be marketed to, so the grant has to come from somewhere. A `transactional` name starts on.

An automation declares only a root, `marketing` or `transactional`. That decides how it enrolls, and whether its webhooks need the recipient's yes to `marketing`. The emails it sends carry their own purposes.

**A promotion is not a transactional purpose.** Nothing mechanical stops you declaring a promotion as `transactional.<name>`, which starts on, or as bare `transactional`, which nobody can leave. Which purpose a message belongs to is a judgement about your own message, so it is yours to make and yours to answer for. Cowliss honors the purpose the template declares; it cannot read the mail. A promotion is marketing, whatever the template calls it. Bare `transactional` is only for mail the person cannot do without, and anything they could do without gets a `transactional.<name>`, so they can at least leave it.

Set consent per user on the `identify` call that already carries their traits, through the [consent endpoint](/reference/api/users/), or in the dashboard's consent editor. Passing it on `identify` is what lets your own signup checkbox be the record:

```ts
await cow.identify({
  identifiers: { userId: "user_1" },
  traits: { email: "ada@acme-demo.io" },
  consent: { "marketing.newsletter": form.newsletter },
});
```

The field is a merge patch: a purpose you omit keeps the value it had, and omitting `consent` entirely changes nothing, so a later `identify` is never an accidental revocation. Granting only `marketing` mails nobody, because every marketing email names a purpose: grant the name. Two automations revoke consent on your behalf: a spam complaint on marketing mail turns off `marketing` and every name under it (on a `transactional.<name>` email, that name alone; on bare `transactional` mail, nothing), and the one-click unsubscribe link every send someone can leave carries turns off the purpose that mail was sent under. "Unsubscribe from everything", on the preferences page the footer links to, turns off both roots instead. Both write a `system.consent_revoked` system event carrying the purpose, so the user timeline always answers "when and why did sends stop".

## Default 3: you own the consent records

Art. 7(1): where processing is based on consent, the controller must be able to **demonstrate** it. Cowliss stores the consent state you supply opaquely. It does not know what your user saw or agreed to. Capturing the agreement (your form, your wording, your timestamp) is yours; the consent map plus the `system.consent_revoked` event stream is the storage Cowliss contributes to your proof.

## Where a recipient leaves

Every email whose purpose someone can withhold carries a signed one-click unsubscribe in its headers. Unless your template renders its own links, it also carries a footer saying who it was sent to and why (the purpose's label), with "Update your email preferences" and "Unsubscribe" (this purpose), then your app's name, website and postal address. A link only opens a confirmation page, because mail scanners follow links. Keep me subscribed is the page's prominent choice and changes nothing; the Unsubscribe button makes the change.

Leaving a purpose turns off that purpose alone. Leaving everything turns off both roots and every name under them, and the page says that account mail such as receipts still arrives. Bare `transactional` mail carries no link, because nobody can withhold it.

The page after the click offers Resubscribe for 48 hours. It puts back exactly what that click turned off, never a purpose the recipient had not granted or had already turned off, and writes a `system.consent_granted` event for each purpose that is on again. The same page asks, optionally, why they left, and records the answer as a `system.unsubscribe_feedback` event on their profile: a reason they picked and up to 500 characters they typed, which is personal data like any other event property. Every email a recipient can leave also links to a hosted [preferences page](/emails/#email-preferences), where they switch each of your app's purposes on or off themselves, and your app can send them there too. Each change writes a `system.consent_revoked` or `system.consent_granted` event with reason `preferences`. Your own app still records consent it collects with `identify`.

## The assist tooling

Data-rights requests land on you; Cowliss's job is making each one call:

- **Erasure**: `DELETE /v1/users/{profileId}` removes a person everywhere, identifiers, events, and automations they are in included. One request answers the request. Also a dashboard action on the user page.
- **Export**: `GET /v1/users/{profileId}/export` returns one JSON document: profile, identifiers, traits, consent, suppressed addresses, event history, and automation/delivery history.
- **Retention**: one "keep events N days" setting for the organization (90 days unless you set another, 18 months at most), applied as each event is written. A write whose timestamp is older than the window is not kept in the raw event log but still counts toward segments; one more than 18 months old is refused with 422. The window governs the raw event log (the event feed and exports); segments do not depend on it, because they count what each person did in a summary kept for as long as the profile, and erased with it. See the [settings reference](/reference/api/settings/).
- **Self-service for your recipients**: the signed one-click unsubscribe every email a recipient can leave carries, as above.

All of it is in the [users API reference](/reference/api/users/). Erasure, export, and retention are API-and-dashboard operations; the CLI and MCP cover the read side plus consent edits.

## The paperwork

- [Data processing agreement](/legal/dpa/): the Art. 28 contract, incorporated into the terms of service.
- [Subprocessors](/legal/subprocessors/): who else touches tenant data and where it is hosted; changes are published there.
- [Records of processing](/legal/records-of-processing/): the Art. 30(2) stub, per tenant.

Sign-up asks for express acceptance of the terms of service and privacy policy, which incorporate the DPA, so the controller/processor split binds every organization from its first event.
