---
title: "Legal pages and consent"
url: /interfaces/legal
---

# Legal pages and consent

> Your terms and privacy notice rendered from your own text and the file's facts, accepted by digest, and a site that asks before any tag loads.

The site renders your legal pages from text you supply and facts the file states, and asks a visitor before any tag you add loads.

**A legal page, from your text to accepted.** Your own words.

1. Your text: in the repo.
2. Facts placed (deploy): from the file.
3. Rendered (checked): per locale.
4. Accepted (sign-up or call): by its digest.
5. Changed (a new digest): with notice.

The words are always yours.

## What the site tracks, and consent
The generated site sets no cookie before sign-in, and counts visits without one. So by default it shows no consent prompt.

The portal's session cookie arrives with sign-in and does nothing else. Every tag you add in `consent.tags` waits for the visitor's yes to its category.

| The visitor | The site |
| --- | --- |
| Opens a page | Shows the prompt once, each category apart, refusing in one click as accepting does |
| Refuses, or sends the browser's privacy signal with `gpc` | Loads no tag in that category, and asks again only after a new notice |
| Accepts | Loads the tags of the categories accepted |
| Changes its mind | Uses the footer link on every page, which withdraws at once |

Each choice is a [consent record](/interfaces/legal.md#consent): the categories, the notice version seen and the time, written as an Event.

## Who writes what
APIs.Dev never writes a legal word for your product. You supply the text, and the file supplies the facts it states.

| Page | The words, from | The facts it prints, from the file |
| --- | --- | --- |
| Terms | `legal.terms` | The seller in `legal.entity`, the prices, the refund rule and the licence in `terms` |
| Privacy notice | `legal.privacy` | Each data class kept, the processors, where the data lives and how long |
| Data processing agreement | `legal.dpa`, or the one [governance](/trust/governance.md) generates | Your role per class, the sub-processors and the window for a person's request |
| Imprint | `legal.imprint` | The seller's name, address and contact |
| The refund rule | The Offer | The rule each receipt cites |

Your text places a fact by name, such as the processor list, so a deploy that adds a processor updates the page that lists it. A Live product that charges and has no terms or privacy text is refused at publish with [`legal_missing`](/reference/platform.md#legal_missing).

## Versions and acceptance
Each page has a digest per version, and every old version stays at its own address.

A Customer accepts the terms digest at sign-up; an agent sends it in `Accept-Terms`, and each receipt names it. A change reaches Customers by the notice rule on [agreements and price changes](/commerce/agreements.md#prices).

## Text of your own, one tag
The weekly brief supplies its own terms and privacy notice, and adds one advertising tag behind consent.

```ts title="definition.ts"
import { define, generative } from 'apis.dev'

/** A weekly brief on the software companies that changed headcount, for members and their agents. */
export default define({
  name: 'briefs', domain: 'briefs.apis.dev',
  sources: {
    firms: { api: 'companyfacts.apis.dev', cost: { 'Company.search': 0.005 } },
  },
  Issue: {
    week: 'string!#', title: 'string', body: 'markdown',
    status: {
      draft:   { run: generative('This week in {firms}: who hired, who shrank') },
      review:  { in: 'drafted', role: 'editor' },
      publish: { in: 'reviewed', role: 'editor' },
      send:    { in: 'published', to: 'Member' },
    },
  },
  on: { 'every Mon 06:00': 'Issue.draft', 'Issue.published': 'Issue.send' },
  offer: {
    'Issue.list': 0, 'Issue.read': 0.25,
    Member: { month: 8, includes: { 'Issue.read': 'all' } },
  },
  legal: {
    entity:  'Briefs Media LLC',
    terms:   './legal/terms.md',                // your words
    privacy: './legal/privacy.md',
    contact: 'legal@briefs.apis.dev',
  },
  consent: {
    tags: { ads: { src: 'https://tags.example.com/t.js', category: 'ads' } },
    gpc: true,                                  // the privacy signal refuses
  },
})
```

A visitor who refused advertising leaves this record behind.

```json title="Consent record"
{
  "type": "Consent.recorded",
  "at": "2026-10-28T14:20:05Z",
  "visitor": "vis_8c2e",
  "notice": "sha256:41d0e9a2",
  "choices": { "analytics": true, "ads": false, "support": true },
  "by": "prompt"
}
```