FreePrivacyPolicy

Intégrez les pages légales à votre app

Une seule requête rédige votre politique de confidentialité, vos CGU, votre CLUF et vos normes de protection de l'enfance, et les héberge avec une page d'entreprise et un app-ads.txt sur {slug}.freeprivacypolicy.app. Gratuit, sans limite de politiques.

Endpoints
16
Limite de requêtes
60/min
Spécification
OpenAPI 3.1

POST /api/v1/policies

{
    "name": "Pocket Notes",
    "product_type": "mobile_app",
    "country": "Portugal",
    "services": [
        "admob",
        "firebase_analytics"
    ]
}

201 Created, en ligne

  • pocket-notes.freeprivacypolicy.app/ (Page de l'entreprise)
  • pocket-notes.freeprivacypolicy.app/privacy-policy (Politique de confidentialité)
  • pocket-notes.freeprivacypolicy.app/terms-of-service (Conditions générales d'utilisation)
  • pocket-notes.freeprivacypolicy.app/end-user-license-agreement (CLUF)
  • pocket-notes.freeprivacypolicy.app/child-safety-standards (Normes de protection de l'enfance)
  • pocket-notes.freeprivacypolicy.app/ads.txt (ads.txt)
  • pocket-notes.freeprivacypolicy.app/app-ads.txt (app-ads.txt)
Sur cette page

Démarrage rapide

Trois étapes pour passer de rien à une URL de politique de confidentialité à coller dans App Store Connect ou Google Play.

  1. Créer un compte gratuit

    Les politiques, les entreprises et la clé appartiennent toutes à votre compte. Aucune offre à choisir, aucune carte à ajouter.

  2. Créez votre clé personnelle

    Ouvrez la page de l'assistant et sélectionnez Créer ma clé. Elle n'est affichée qu'une fois : conservez-la immédiatement, par exemple dans FPP_API_KEY de vos secrets de CI ou de votre shell.

    Shell
    export FPP_API_KEY="fpp_your_key_here"
  3. Publiez votre première politique

    Envoyez le nom, le type de produit et votre pays. Ajoutez les services utilisés par votre app pour que la politique les mentionne.

    Requête
    curl -X POST "https://freeprivacypolicy.app/api/v1/policies" \
      -H "Authorization: Bearer $FPP_API_KEY" \
      -H "Accept: application/json" \
      -H "Content-Type: application/json" \
      -d '{"name": "Pocket Notes", "product_type": "mobile_app", "country": "Portugal", "services": ["admob", "firebase_analytics"]}'

    La réponse contient toutes les adresses, déjà en ligne :

    Réponse 201
    {
        "data": {
            "slug": "pocket-notes",
            "name": "Pocket Notes",
            "published": true,
            "public_urls": {
                "landing": "https://pocket-notes.freeprivacypolicy.app",
                "privacy_policy": "https://pocket-notes.freeprivacypolicy.app/privacy-policy",
                "terms": "https://pocket-notes.freeprivacypolicy.app/terms-of-service",
                "eula": "https://pocket-notes.freeprivacypolicy.app/end-user-license-agreement",
                "child_safety": "https://pocket-notes.freeprivacypolicy.app/child-safety-standards",
                "ads_txt": "https://pocket-notes.freeprivacypolicy.app/ads.txt",
                "app_ads_txt": "https://pocket-notes.freeprivacypolicy.app/app-ads.txt"
            }
        }
    }

Authentification

Chaque requête transporte votre clé personnelle, dans l'un ou l'autre en-tête. Les requêtes sans clé valide reçoivent 401.

  • Une clé, deux usages. La même clé connecte Claude Code et Codex via MCP et appelle l'API REST.
  • Une nouvelle clé remplace l'ancienne. Créer une clé déconnecte partout et immédiatement la clé précédente.
  • Uniquement votre compte. Une clé ne lit et ne modifie que vos propres politiques et entreprises. Les enregistrements d'autres comptes répondent 404.
  • Gardez-la côté serveur. N'intégrez jamais la clé dans le binaire d'une app ou dans une page web. Appelez l'API depuis la CI, un backend ou votre machine.
  • 60 requêtes par minute par clé. Chaque réponse contient X-RateLimit-Remaining.
curl "https://freeprivacypolicy.app/api/v1/me" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"

Recettes d'intégration

Des scénarios prêts à copier pour les tâches que les développeurs automatisent le plus. Choisissez un langage une fois et tous les exemples de la page suivent.

Publish the policy when you ship

Run this in your release pipeline. It creates the policy the first time and updates it on every release after that, so the hosted text always matches the SDKs in the build you ship.

  • Store the key as a secret named FPP_API_KEY. Never commit it.
  • If the slug you ask for is taken, the API adds a suffix (pocket-notes-2). Keep the slug it returns.
  • A PATCH that changes settings writes the text again. Text you edited by hand in the dashboard is replaced only when you send markdown.
# .github/workflows/privacy-policy.yml
name: Privacy policy

on:
  push:
    tags: ["v*"]

jobs:
  publish:
    runs-on: ubuntu-latest
    steps:
      - name: Create or update the hosted policy
        env:
          FPP_API_KEY: ${{ secrets.FPP_API_KEY }}
          API: https://freeprivacypolicy.app/api/v1
          SLUG: pocket-notes
        run: |
          SETTINGS='{"name":"Pocket Notes","product_type":"mobile_app","country":"Portugal","services":["admob","firebase_analytics","revenuecat"]}'
          AUTH=(-H "Authorization: Bearer $FPP_API_KEY" -H "Accept: application/json" -H "Content-Type: application/json")

          STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${AUTH[@]}" "$API/policies/$SLUG")

          if [ "$STATUS" = "404" ]; then
            curl -fsS -X POST "$API/policies" "${AUTH[@]}" \
              -d "$(echo "$SETTINGS" | jq --arg slug "$SLUG" '. + {slug: $slug}')"
          else
            curl -fsS -X PATCH "$API/policies/$SLUG" "${AUTH[@]}" -d "$SETTINGS"
          fi

Fill in App Store Connect and Google Play

Every policy response carries public_urls. Paste them into the store fields below once; the addresses never change, even when you update the text.

App Store Connect: Privacy Policy URL
privacy_policy
App Store Connect: License Agreement (custom EULA)
eula
Google Play Console: Privacy policy
privacy_policy
Google Play Console: Child safety standards
child_safety
Store listing: Website (used by ad networks for app-ads.txt)
landing
Terms link inside your app or website
terms
curl -s "https://freeprivacypolicy.app/api/v1/policies/pocket-notes" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  | jq '.data.public_urls'

Keep app-ads.txt in sync for ad networks

AdMob, AppLovin, Unity and other networks read app-ads.txt from the website on your store listing. Set that website to the policy address (public_urls.landing) and keep the lines on your company: every policy subdomain serves the lines of all your companies, merged and without duplicates.

  • Send the whole file: app_ads_txt replaces the previous lines.
  • Changes are live at https://{slug}.freeprivacypolicy.app/app-ads.txt right away. Ad networks re-crawl on their own schedule, usually within 24 hours.
  • ads_txt works the same way for websites and is served per company.
curl -X PATCH "https://freeprivacypolicy.app/api/v1/companies/42" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0\napplovin.com, 0123456789abcdef, DIRECT"
  }'

# Check what ad networks will read
curl -s https://pocket-notes.freeprivacypolicy.app/app-ads.txt

Update the policy when you add an SDK

Each service adds its own disclosure. services replaces the whole list, so read the current one, add the new key and send it back. Valid keys come from GET /options.

SERVICES=$(curl -s "https://freeprivacypolicy.app/api/v1/policies/pocket-notes" \
  -H "Authorization: Bearer $FPP_API_KEY" -H "Accept: application/json" \
  | jq -c '.data.services + ["openai"] | unique')

curl -X PATCH "https://freeprivacypolicy.app/api/v1/policies/pocket-notes" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d "{\"services\": $SERVICES, \"clauses\": [\"accounts\", \"ai\"]}"

Share one company across several apps

A company holds the publisher details shown on every page, plus ads.txt and app-ads.txt. Create it once, then pass its id as company_id to each new policy. Upload a logo in the dashboard; the API does not accept files.

# 1. Create the company
curl -X POST "https://freeprivacypolicy.app/api/v1/companies" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"company_name": "Acme Labs Ltd.", "email": "[email protected]", "address": "1 Market Street, Lisbon"}'

# 2. Publish each app with its id
curl -X POST "https://freeprivacypolicy.app/api/v1/policies" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name": "Pocket Notes", "product_type": "mobile_app", "country": "Portugal", "company_id": 42}'

# 3. List everything in the account
curl -s "https://freeprivacypolicy.app/api/v1/companies?per_page=100" -H "Authorization: Bearer $FPP_API_KEY" -H "Accept: application/json"

Serveur MCP à l'adresse https://freeprivacypolicy.app/mcp

Vous préférez demander à votre assistant IA ?

La même clé connecte Claude Code, Claude Desktop, Codex, Cursor et VS Code. L'assistant lit vos dépendances, choisit les services que votre app utilise réellement et appelle ces endpoints pour vous : publication, mise à jour, entreprises, app-ads.txt.

Claude Code par Anthropic

Exécuter dans votre terminal
claude mcp add --transport http --scope user freeprivacypolicy https://freeprivacypolicy.app/mcp --header "Authorization: Bearer YOUR_KEY"

Claude Desktop par Anthropic

claude_desktop_config.json
{
    "mcpServers": {
        "freeprivacypolicy": {
            "command": "npx",
            "args": [
                "-y",
                "mcp-remote",
                "https://freeprivacypolicy.app/mcp",
                "--header",
                "Authorization:${AUTH_HEADER}",
                "--transport",
                "http-only"
            ],
            "env": {
                "AUTH_HEADER": "Bearer YOUR_KEY"
            }
        }
    }
}

Codex par OpenAI

~/.codex/config.toml
[mcp_servers.freeprivacypolicy]
url = "https://freeprivacypolicy.app/mcp"
http_headers = { "Authorization" = "Bearer YOUR_KEY" }

Cursor par Anysphere

~/.cursor/mcp.json
{
    "mcpServers": {
        "freeprivacypolicy": {
            "url": "https://freeprivacypolicy.app/mcp",
            "headers": {
                "Authorization": "Bearer YOUR_KEY"
            }
        }
    }
}

Cursor l'installe aussi depuis un lien : connectez-vous et connectez Cursor pour obtenir le vôtre avec la clé déjà renseignée.

VS Code par Microsoft · mode agent de GitHub Copilot

Exécuter dans votre terminal
code --add-mcp '{"name":"freeprivacypolicy","type":"http","url":"https://freeprivacypolicy.app/mcp","headers":{"Authorization":"Bearer YOUR_KEY"}}'

VS Code l'installe aussi depuis un lien : connectez-vous et connectez VS Code pour obtenir le vôtre avec la clé déjà renseignée.

Connecter un assistant

Référence de l'API

Généré à partir du document OpenAPI, version 1.0.0.

URL de base https://freeprivacypolicy.app/api/v1

Account

The account the API key belongs to.

Get the current account

GET /me

Returns the account the API key belongs to, with how many policies and companies it has. Handy to check that a key works.

Réponses
  • 200

    The account.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 429

    More than 60 requests in a minute with this key.

curl -X GET "https://freeprivacypolicy.app/api/v1/me" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"
Réponse 200
{
    "data": {
        "id": 7,
        "name": "Ada Lovelace",
        "email": "[email protected]",
        "policies_count": 2,
        "companies_count": 1
    }
}

Catalog

Product types, third-party services, optional sections and countries a policy can use.

List policy options

GET /options

Everything a policy can cover: product types, third-party services (each adds its own disclosure), optional sections, document languages and countries. Use the key values in product_type, services and clauses, a country name in country and a language code in language.

Réponses
  • 200

    The catalog.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 429

    More than 60 requests in a minute with this key.

curl -X GET "https://freeprivacypolicy.app/api/v1/options" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"
Réponse 200
{
    "data": {
        "product_types": [
            {
                "key": "mobile_app",
                "label": "Mobile App"
            }
        ],
        "services": [
            {
                "key": "admob",
                "label": "AdMob",
                "group": "Ads",
                "description": "We use Google AdMob to serve personalized and non-personalized ads in our product...",
                "products": [
                    "mobile_app",
                    "game"
                ],
                "ads": true
            }
        ],
        "clauses": [
            {
                "key": "accounts",
                "label": "Accounts and sign-in",
                "category": "Data you collect",
                "description": "Explain the details collected when people create an account."
            }
        ],
        "languages": [
            {
                "code": "en",
                "name": "English"
            },
            {
                "code": "pt_BR",
                "name": "Português (Brasil)"
            }
        ],
        "countries": [
            {
                "code": "PT",
                "name": "Portugal"
            }
        ]
    }
}

Policies

Generate, publish, update and take down the legal pages hosted on {slug}.freeprivacypolicy.app.

List policies

GET /policies

Your policies, published or not, sorted by name.

Paramètres
  • page integer dans query

    Page number, starting at 1. Par défaut : 1.

  • per_page integer dans query

    Items per page, 1 to 100. Par défaut : 25.

Réponses
  • 200

    A page of policies.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 422

    The request is invalid. errors lists the messages per field.

  • 429

    More than 60 requests in a minute with this key.

curl -X GET "https://freeprivacypolicy.app/api/v1/policies?per_page=25" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"
Réponse 200
{
    "data": [
        {
            "id": 1287,
            "slug": "pocket-notes",
            "name": "Pocket Notes",
            "product_type": "mobile_app",
            "country": "Portugal",
            "services": [
                "admob",
                "firebase_analytics",
                "revenuecat"
            ],
            "clauses": [
                "accounts",
                "metadata"
            ],
            "markdown": "# Privacy Policy\n\nThis Privacy Policy explains how Acme Labs Ltd. collects, uses and protects information when you use Pocket Notes...",
            "html": "<h1>Privacy Policy</h1>\n<p>This Privacy Policy explains how Acme Labs Ltd. collects, uses and protects information when you use Pocket Notes...</p>",
            "published": true,
            "published_at": "2026-09-20T08:30:00+00:00",
            "noindex": false,
            "company_id": 42,
            "contact": {
                "id": 42,
                "company_name": "Acme Labs Ltd.",
                "address": "1 Market Street, Lisbon, Portugal",
                "email": "[email protected]",
                "about": "Acme Labs builds productivity apps for small teams.",
                "ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
                "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
                "show_resources_publicly": true
            },
            "public_urls": {
                "landing": "https://pocket-notes.freeprivacypolicy.app",
                "privacy_policy": "https://pocket-notes.freeprivacypolicy.app/privacy-policy",
                "child_safety": "https://pocket-notes.freeprivacypolicy.app/child-safety-standards",
                "eula": "https://pocket-notes.freeprivacypolicy.app/end-user-license-agreement",
                "terms": "https://pocket-notes.freeprivacypolicy.app/terms-of-service",
                "ads_txt": "https://pocket-notes.freeprivacypolicy.app/ads.txt",
                "app_ads_txt": "https://pocket-notes.freeprivacypolicy.app/app-ads.txt"
            },
            "created_at": "2026-09-20T08:30:00+00:00",
            "updated_at": "2026-09-20T08:30:00+00:00"
        }
    ],
    "links": {
        "first": "https://freeprivacypolicy.app/api/v1/policies?page=1",
        "last": "https://freeprivacypolicy.app/api/v1/policies?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "page": null,
                "active": false
            },
            {
                "url": "https://freeprivacypolicy.app/api/v1/policies?page=1",
                "label": "1",
                "page": 1,
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "page": null,
                "active": false
            }
        ],
        "path": "https://freeprivacypolicy.app/api/v1/policies",
        "per_page": 25,
        "to": 1,
        "total": 1
    }
}

Generate and publish a policy

POST /policies

Writes the policy from the settings you send and publishes it right away on {slug}.freeprivacypolicy.app.

The publisher shown on the pages comes from, in order:

  1. company_id: one of your companies (GET /companies), shared between policies;
  2. contact: a new company used only by this policy;
  3. nothing: a new company named after the policy, with {slug}@freeprivacypolicy.app as the email.

company_id and contact cannot be sent together.

Corps PolicyInput
  • name string obligatoire

    Name of the app, game, website or company, as users know it.

  • product_type string obligatoire

    What the product is. See GET /options for labels.

    website mobile_app saas game desktop_app browser_extension

  • country string obligatoire

    Country you operate from, as an English name (see countries in GET /options).

  • language string

    Language the legal documents and public pages are written in (see languages in GET /options). Defaults to en.

    Par défaut : "en".

    en pt_BR es fr de it ja

  • services string[] | null

    Third-party services the product uses. Each one adds its own disclosure. Replaces the whole list on update.

    37 valeurs acceptées

    admob facebook_audience_network facebook_pixel firebase_analytics firebase_crashlytics google_analytics google_sign_in sign_in_with_apple facebook_login firebase_cloud_messaging onesignal revenuecat stripe sentry mixpanel amplitude appsflyer unity_ads applovin google_maps openai qonversion adapty superwall adjust branch ironsource paddle auth0 clerk posthog segment hotjar intercom hubspot zendesk anthropic

  • clauses string[] | null

    Optional sections, such as accounts, location or gdpr. Replaces the whole list on update.

    30 valeurs acceptées

    accounts metadata location contacts camera_media microphone biometrics health purchases financial identity_verification credit_partners notifications marketing ugc ai advertising analytics no_sale retention account_deletion international_transfers third_party_links children gdpr ccpa lgpd us_states canada mexico

  • slug string | null

    Subdomain of the public pages ({slug}.freeprivacypolicy.app). Lowercase letters, numbers and hyphens; defaults to the name. When taken, a numeric suffix is added (pocket-notes-2); reserved words (www, api, docs, ...) are rejected with 422.

  • markdown string | null

    Your own policy text in Markdown. When sent, it is published as given instead of the generated text.

  • noindex boolean | null

    true asks search engines not to index the public pages (they stay online).

    Par défaut : false.

  • company_id integer | null

    Id of one of your companies (GET /companies). Its contact details, logo and ads.txt are used. Cannot be combined with contact.

  • contact object

    Publisher details for a company used only by this policy.

  • contact.company_name string

    Legal or trading name shown as the publisher. Defaults to the policy name.

  • contact.email string

    Where users reach you about privacy. When left out on create, {slug}@freeprivacypolicy.app is used.

  • contact.address string | null

    Postal address, only when you want it published.

  • contact.about string | null

    Short description shown on the company page.

  • contact.ads_txt string | null

    Full ads.txt content for websites, one seller line per row.

  • contact.app_ads_txt string | null

    Full app-ads.txt content for mobile apps, one seller line per row.

  • contact.show_resources_publicly boolean

    List the ads.txt and app-ads.txt links on the company page.

    Par défaut : false.

  • accent_color string | null

    Accent color of the public pages as #RRGGBB, or null for the default. Links and buttons use it; text shades are darkened automatically to keep AA contrast.

  • theme string

    Look of the public pages: classic (default), minimal (plain document) or card (document on a raised card under a band in the accent color).

    Par défaut : "classic".

    classic minimal card

Réponses
  • 201

    The policy was published.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 422

    The request is invalid. errors lists the messages per field.

  • 429

    More than 60 requests in a minute with this key.

curl -X POST "https://freeprivacypolicy.app/api/v1/policies" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Pocket Notes",
    "product_type": "mobile_app",
    "country": "Portugal",
    "services": [
        "admob",
        "firebase_analytics",
        "revenuecat"
    ],
    "clauses": [
        "accounts",
        "metadata"
    ],
    "slug": "pocket-notes",
    "contact": {
        "company_name": "Acme Labs Ltd.",
        "email": "[email protected]",
        "address": "1 Market Street, Lisbon, Portugal",
        "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
        "show_resources_publicly": true
    }
}'
Corps de la requête : Only the required fields
{
    "name": "Pocket Notes",
    "product_type": "mobile_app",
    "country": "Portugal"
}
Réponse 201
{
    "data": {
        "id": 1287,
        "slug": "pocket-notes",
        "name": "Pocket Notes",
        "product_type": "mobile_app",
        "country": "Portugal",
        "language": "en",
        "services": [
            "admob",
            "firebase_analytics",
            "revenuecat"
        ],
        "clauses": [
            "accounts",
            "metadata"
        ],
        "markdown": "# Privacy Policy\n\nThis Privacy Policy explains how Acme Labs Ltd. collects, uses and protects information when you use Pocket Notes...",
        "html": "<h1>Privacy Policy</h1>\n<p>This Privacy Policy explains how Acme Labs Ltd. collects, uses and protects information when you use Pocket Notes...</p>",
        "published": true,
        "published_at": "2026-09-20T08:30:00+00:00",
        "noindex": false,
        "app_icon_url": null,
        "logo_url": null,
        "accent_color": null,
        "theme": "classic",
        "company_id": 42,
        "contact": {
            "id": 42,
            "company_name": "Acme Labs Ltd.",
            "address": "1 Market Street, Lisbon, Portugal",
            "email": "[email protected]",
            "about": "Acme Labs builds productivity apps for small teams.",
            "ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
            "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
            "show_resources_publicly": true
        },
        "public_urls": {
            "landing": "https://pocket-notes.freeprivacypolicy.app",
            "privacy_policy": "https://pocket-notes.freeprivacypolicy.app/privacy-policy",
            "child_safety": "https://pocket-notes.freeprivacypolicy.app/child-safety-standards",
            "eula": "https://pocket-notes.freeprivacypolicy.app/end-user-license-agreement",
            "terms": "https://pocket-notes.freeprivacypolicy.app/terms-of-service",
            "ads_txt": "https://pocket-notes.freeprivacypolicy.app/ads.txt",
            "app_ads_txt": "https://pocket-notes.freeprivacypolicy.app/app-ads.txt"
        },
        "created_at": "2026-09-20T08:30:00+00:00",
        "updated_at": "2026-09-20T08:30:00+00:00"
    }
}

Get a policy

GET /policies/{slug}

One of your policies, with its Markdown and HTML text and the addresses of its public pages.

Paramètres
  • slug string dans path obligatoire

    The policy slug (its subdomain).

Réponses
  • 200

    The policy.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 404

    No such record in this account.

  • 429

    More than 60 requests in a minute with this key.

curl -X GET "https://freeprivacypolicy.app/api/v1/policies/pocket-notes" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"
Réponse 200
{
    "data": {
        "id": 1287,
        "slug": "pocket-notes",
        "name": "Pocket Notes",
        "product_type": "mobile_app",
        "country": "Portugal",
        "language": "en",
        "services": [
            "admob",
            "firebase_analytics",
            "revenuecat"
        ],
        "clauses": [
            "accounts",
            "metadata"
        ],
        "markdown": "# Privacy Policy\n\nThis Privacy Policy explains how Acme Labs Ltd. collects, uses and protects information when you use Pocket Notes...",
        "html": "<h1>Privacy Policy</h1>\n<p>This Privacy Policy explains how Acme Labs Ltd. collects, uses and protects information when you use Pocket Notes...</p>",
        "published": true,
        "published_at": "2026-09-20T08:30:00+00:00",
        "noindex": false,
        "app_icon_url": null,
        "logo_url": null,
        "accent_color": null,
        "theme": "classic",
        "company_id": 42,
        "contact": {
            "id": 42,
            "company_name": "Acme Labs Ltd.",
            "address": "1 Market Street, Lisbon, Portugal",
            "email": "[email protected]",
            "about": "Acme Labs builds productivity apps for small teams.",
            "ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
            "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
            "show_resources_publicly": true
        },
        "public_urls": {
            "landing": "https://pocket-notes.freeprivacypolicy.app",
            "privacy_policy": "https://pocket-notes.freeprivacypolicy.app/privacy-policy",
            "child_safety": "https://pocket-notes.freeprivacypolicy.app/child-safety-standards",
            "eula": "https://pocket-notes.freeprivacypolicy.app/end-user-license-agreement",
            "terms": "https://pocket-notes.freeprivacypolicy.app/terms-of-service",
            "ads_txt": "https://pocket-notes.freeprivacypolicy.app/ads.txt",
            "app_ads_txt": "https://pocket-notes.freeprivacypolicy.app/app-ads.txt"
        },
        "created_at": "2026-09-20T08:30:00+00:00",
        "updated_at": "2026-09-20T08:30:00+00:00"
    }
}

Update a policy

PATCH /policies/{slug}

Only the fields you send change.

  • Settings (name, product_type, country, language, services, clauses, contact, company_id) regenerate the text, which replaces edits made by hand. Send markdown in the same request to keep your own text.
  • markdown alone replaces the text as given.
  • published: false takes every public page offline (404); true puts them back.
  • noindex and slug never touch the text.
  • company_id: null detaches the company; the pages then use the contact details saved with the policy.
Paramètres
  • slug string dans path obligatoire

    The policy slug (its subdomain).

Corps PolicyUpdate
  • name string

    Name of the app, game, website or company, as users know it.

  • product_type string

    What the product is. See GET /options for labels.

    website mobile_app saas game desktop_app browser_extension

  • country string

    Country you operate from, as an English name (see countries in GET /options).

  • language string

    Language the legal documents and public pages are written in. Changing it regenerates the text, like the other settings.

    en pt_BR es fr de it ja

  • services string[] | null

    Third-party services the product uses. Each one adds its own disclosure. Replaces the whole list on update.

    37 valeurs acceptées

    admob facebook_audience_network facebook_pixel firebase_analytics firebase_crashlytics google_analytics google_sign_in sign_in_with_apple facebook_login firebase_cloud_messaging onesignal revenuecat stripe sentry mixpanel amplitude appsflyer unity_ads applovin google_maps openai qonversion adapty superwall adjust branch ironsource paddle auth0 clerk posthog segment hotjar intercom hubspot zendesk anthropic

  • clauses string[] | null

    Optional sections, such as accounts, location or gdpr. Replaces the whole list on update.

    30 valeurs acceptées

    accounts metadata location contacts camera_media microphone biometrics health purchases financial identity_verification credit_partners notifications marketing ugc ai advertising analytics no_sale retention account_deletion international_transfers third_party_links children gdpr ccpa lgpd us_states canada mexico

  • slug string | null

    Subdomain of the public pages ({slug}.freeprivacypolicy.app). Lowercase letters, numbers and hyphens; defaults to the name. When taken, a numeric suffix is added (pocket-notes-2); reserved words (www, api, docs, ...) are rejected with 422.

  • markdown string | null

    Your own policy text in Markdown. When sent, it is published as given instead of the generated text.

  • company_id integer | null

    Id of one of your companies, or null to detach the current one. Cannot be combined with contact.

  • contact object

    Publisher details for a company used only by this policy.

  • contact.company_name string

    Legal or trading name shown as the publisher. Defaults to the policy name.

  • contact.email string

    Where users reach you about privacy. When left out on create, {slug}@freeprivacypolicy.app is used.

  • contact.address string | null

    Postal address, only when you want it published.

  • contact.about string | null

    Short description shown on the company page.

  • contact.ads_txt string | null

    Full ads.txt content for websites, one seller line per row.

  • contact.app_ads_txt string | null

    Full app-ads.txt content for mobile apps, one seller line per row.

  • contact.show_resources_publicly boolean

    List the ads.txt and app-ads.txt links on the company page.

    Par défaut : false.

  • noindex boolean

    true asks search engines not to index the public pages (they stay online).

  • published boolean

    false takes every public page offline (404); true publishes them again.

  • accent_color string | null

    Accent color of the public pages as #RRGGBB, or null for the default. Links and buttons use it; text shades are darkened automatically to keep AA contrast.

  • theme string

    Look of the public pages: classic (default), minimal (plain document) or card (document on a raised card under a band in the accent color).

    Par défaut : "classic".

    classic minimal card

Réponses
  • 200

    The updated policy.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 404

    No such record in this account.

  • 422

    The request is invalid. errors lists the messages per field.

  • 429

    More than 60 requests in a minute with this key.

curl -X PATCH "https://freeprivacypolicy.app/api/v1/policies/pocket-notes" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "services": [
        "admob",
        "firebase_analytics",
        "revenuecat",
        "openai"
    ],
    "clauses": [
        "accounts",
        "metadata",
        "ai"
    ]
}'
Corps de la requête : Add a service and a section
{
    "services": [
        "admob",
        "firebase_analytics",
        "revenuecat",
        "openai"
    ],
    "clauses": [
        "accounts",
        "metadata",
        "ai"
    ]
}
Réponse 200
{
    "data": {
        "id": 1287,
        "slug": "pocket-notes",
        "name": "Pocket Notes",
        "product_type": "mobile_app",
        "country": "Portugal",
        "language": "en",
        "services": [
            "admob",
            "firebase_analytics",
            "revenuecat"
        ],
        "clauses": [
            "accounts",
            "metadata"
        ],
        "markdown": "# Privacy Policy\n\nThis Privacy Policy explains how Acme Labs Ltd. collects, uses and protects information when you use Pocket Notes...",
        "html": "<h1>Privacy Policy</h1>\n<p>This Privacy Policy explains how Acme Labs Ltd. collects, uses and protects information when you use Pocket Notes...</p>",
        "published": true,
        "published_at": "2026-09-20T08:30:00+00:00",
        "noindex": false,
        "app_icon_url": null,
        "logo_url": null,
        "accent_color": null,
        "theme": "classic",
        "company_id": 42,
        "contact": {
            "id": 42,
            "company_name": "Acme Labs Ltd.",
            "address": "1 Market Street, Lisbon, Portugal",
            "email": "[email protected]",
            "about": "Acme Labs builds productivity apps for small teams.",
            "ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
            "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
            "show_resources_publicly": true
        },
        "public_urls": {
            "landing": "https://pocket-notes.freeprivacypolicy.app",
            "privacy_policy": "https://pocket-notes.freeprivacypolicy.app/privacy-policy",
            "child_safety": "https://pocket-notes.freeprivacypolicy.app/child-safety-standards",
            "eula": "https://pocket-notes.freeprivacypolicy.app/end-user-license-agreement",
            "terms": "https://pocket-notes.freeprivacypolicy.app/terms-of-service",
            "ads_txt": "https://pocket-notes.freeprivacypolicy.app/ads.txt",
            "app_ads_txt": "https://pocket-notes.freeprivacypolicy.app/app-ads.txt"
        },
        "created_at": "2026-09-20T08:30:00+00:00",
        "updated_at": "2026-09-20T08:30:00+00:00"
    }
}

Delete a policy

DELETE /policies/{slug}

Deletes the policy for good. Its public pages answer 404 and the slug becomes free. Its company is kept. To only take the pages offline, send published: false instead.

Paramètres
  • slug string dans path obligatoire

    The policy slug (its subdomain).

Réponses
  • 204

    Deleted.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 404

    No such record in this account.

  • 429

    More than 60 requests in a minute with this key.

curl -X DELETE "https://freeprivacypolicy.app/api/v1/policies/pocket-notes" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"

204 n'a pas de corps.

Upload the app icon

POST /policies/{slug}/app-icon

Sends the app icon as multipart/form-data. It must be a square PNG, JPG or WebP of at least 128 × 128 px and up to 1 MB. The public pages show it next to the name and use it as favicon, touch icon and share image. Replaces the current icon.

Paramètres
  • slug string dans path obligatoire

    The policy slug (its subdomain).

Corps
  • app_icon string obligatoire

    Square PNG, JPG or WebP, at least 128 × 128 px, up to 1 MB.

Réponses
  • 200

    The policy with its new app_icon_url.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 404

    No such record in this account.

  • 429

    More than 60 requests in a minute with this key.

  • 422

    The request is invalid. errors lists the messages per field.

curl -X POST "https://freeprivacypolicy.app/api/v1/policies/pocket-notes/app-icon" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -F "[email protected]"

200 n'a pas de corps.

Remove the app icon

DELETE /policies/{slug}/app-icon

Deletes the app icon. The pages fall back to the company logo, or to the initial of the name.

Paramètres
  • slug string dans path obligatoire

    The policy slug (its subdomain).

Réponses
  • 200

    The policy, with app_icon_url null.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 404

    No such record in this account.

  • 429

    More than 60 requests in a minute with this key.

curl -X DELETE "https://freeprivacypolicy.app/api/v1/policies/pocket-notes/app-icon" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"

200 n'a pas de corps.

Companies

Publisher details shown on the policy pages, their logo, plus the ads.txt and app-ads.txt lines they serve.

List companies

GET /companies

Your companies, sorted by name, with how many policies use each one.

Paramètres
  • page integer dans query

    Page number, starting at 1. Par défaut : 1.

  • per_page integer dans query

    Items per page, 1 to 100. Par défaut : 25.

Réponses
  • 200

    A page of companies.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 422

    The request is invalid. errors lists the messages per field.

  • 429

    More than 60 requests in a minute with this key.

curl -X GET "https://freeprivacypolicy.app/api/v1/companies?per_page=25" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"
Réponse 200
{
    "data": [
        {
            "id": 42,
            "company_name": "Acme Labs Ltd.",
            "email": "[email protected]",
            "address": "1 Market Street, Lisbon, Portugal",
            "about": "Acme Labs builds productivity apps for small teams.",
            "ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
            "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
            "show_resources_publicly": true,
            "logo_url": null,
            "policies_count": 2,
            "created_at": "2026-09-01T12:00:00+00:00",
            "updated_at": "2026-09-20T08:30:00+00:00"
        }
    ],
    "links": {
        "first": "https://freeprivacypolicy.app/api/v1/companies?page=1",
        "last": "https://freeprivacypolicy.app/api/v1/companies?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 1,
        "links": [
            {
                "url": null,
                "label": "&laquo; Previous",
                "page": null,
                "active": false
            },
            {
                "url": "https://freeprivacypolicy.app/api/v1/companies?page=1",
                "label": "1",
                "page": 1,
                "active": true
            },
            {
                "url": null,
                "label": "Next &raquo;",
                "page": null,
                "active": false
            }
        ],
        "path": "https://freeprivacypolicy.app/api/v1/companies",
        "per_page": 25,
        "to": 1,
        "total": 1
    }
}

Create a company

POST /companies

Creates a publisher you can attach to policies with company_id.

ads_txt is served at {slug}/ads.txt for the policies using this company. app_ads_txt lines of all your companies are merged, de-duplicated and served at {slug}/app-ads.txt on every one of your policies.

Logos are uploaded in the dashboard; the API returns logo_url but does not accept files.

Corps CompanyInput
  • company_name string obligatoire

  • email string obligatoire

  • address string | null

  • about string | null

  • ads_txt string | null

    Full ads.txt content, one seller line per row.

  • app_ads_txt string | null

    Full app-ads.txt content, one seller line per row.

  • show_resources_publicly boolean

    List the ads.txt and app-ads.txt links on the company page.

    Par défaut : false.

Réponses
  • 201

    The company was created.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 422

    The request is invalid. errors lists the messages per field.

  • 429

    More than 60 requests in a minute with this key.

curl -X POST "https://freeprivacypolicy.app/api/v1/companies" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "company_name": "Acme Labs Ltd.",
    "email": "[email protected]",
    "address": "1 Market Street, Lisbon, Portugal",
    "about": "Acme Labs builds productivity apps for small teams.",
    "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0\nunity.com, 1234567, DIRECT, 96cabb5fbdde37a7",
    "show_resources_publicly": true
}'
Corps de la requête : Company with app-ads.txt lines
{
    "company_name": "Acme Labs Ltd.",
    "email": "[email protected]",
    "address": "1 Market Street, Lisbon, Portugal",
    "about": "Acme Labs builds productivity apps for small teams.",
    "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0\nunity.com, 1234567, DIRECT, 96cabb5fbdde37a7",
    "show_resources_publicly": true
}
Réponse 201
{
    "data": {
        "id": 42,
        "company_name": "Acme Labs Ltd.",
        "email": "[email protected]",
        "address": "1 Market Street, Lisbon, Portugal",
        "about": "Acme Labs builds productivity apps for small teams.",
        "ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
        "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
        "show_resources_publicly": true,
        "logo_url": null,
        "policies_count": 0,
        "created_at": "2026-09-01T12:00:00+00:00",
        "updated_at": "2026-09-20T08:30:00+00:00"
    }
}

Get a company

GET /companies/{id}

One of your companies.

Paramètres
  • id integer dans path obligatoire

    The company id.

Réponses
  • 200

    The company.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 404

    No such record in this account.

  • 429

    More than 60 requests in a minute with this key.

curl -X GET "https://freeprivacypolicy.app/api/v1/companies/42" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"
Réponse 200
{
    "data": {
        "id": 42,
        "company_name": "Acme Labs Ltd.",
        "email": "[email protected]",
        "address": "1 Market Street, Lisbon, Portugal",
        "about": "Acme Labs builds productivity apps for small teams.",
        "ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
        "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
        "show_resources_publicly": true,
        "logo_url": null,
        "policies_count": 2,
        "created_at": "2026-09-01T12:00:00+00:00",
        "updated_at": "2026-09-20T08:30:00+00:00"
    }
}

Update a company

PATCH /companies/{id}

Only the fields you send change. ads_txt and app_ads_txt replace the whole file: send the current lines too when adding one. The policy pages show the new details at once; their text is not regenerated.

Paramètres
  • id integer dans path obligatoire

    The company id.

Corps CompanyUpdate
  • company_name string

  • email string

  • address string | null

  • about string | null

  • ads_txt string | null

  • app_ads_txt string | null

  • show_resources_publicly boolean

Réponses
  • 200

    The updated company.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 404

    No such record in this account.

  • 422

    The request is invalid. errors lists the messages per field.

  • 429

    More than 60 requests in a minute with this key.

curl -X PATCH "https://freeprivacypolicy.app/api/v1/companies/42" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
    "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0\napplovin.com, 0123456789abcdef, DIRECT"
}'
Corps de la requête : Replace the app-ads.txt lines
{
    "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0\napplovin.com, 0123456789abcdef, DIRECT"
}
Réponse 200
{
    "data": {
        "id": 42,
        "company_name": "Acme Labs Ltd.",
        "email": "[email protected]",
        "address": "1 Market Street, Lisbon, Portugal",
        "about": "Acme Labs builds productivity apps for small teams.",
        "ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
        "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0",
        "show_resources_publicly": true,
        "logo_url": null,
        "policies_count": 2,
        "created_at": "2026-09-01T12:00:00+00:00",
        "updated_at": "2026-09-20T08:30:00+00:00"
    }
}

Delete a company

DELETE /companies/{id}

Deletes the company with its logo and its ads.txt and app-ads.txt lines. Policies that used it stay online without a company, using the contact details saved with them.

Paramètres
  • id integer dans path obligatoire

    The company id.

Réponses
  • 204

    Deleted.

  • 401

    The key is missing, invalid, revoked or its account is suspended.

  • 404

    No such record in this account.

  • 429

    More than 60 requests in a minute with this key.

curl -X DELETE "https://freeprivacypolicy.app/api/v1/companies/42" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"

204 n'a pas de corps.

Erreurs

Les erreurs sont en JSON avec un champ message. Les erreurs de validation ajoutent errors, indexé par champ.

Statut Quand
401 Non authentifié La clé est manquante, incorrecte, remplacée par une plus récente, ou son compte est suspendu. Créez une nouvelle clé et mettez à jour votre secret.
404 Introuvable Aucune politique ni entreprise avec ce slug ou cet id n'existe dans ce compte. Listez vos enregistrements avec GET /policies ou GET /companies.
422 Échec de la validation Un champ est manquant ou invalide. errors liste les messages par champ. Vérifiez les clés avec GET /options.
429 Trop de requêtes Plus de 60 requêtes en une minute avec la même clé. Attendez le nombre de secondes indiqué dans Retry-After, puis réessayez.
5xx Erreur serveur Une erreur s'est produite de notre côté. Réessayez avec un délai croissant. Avant de répéter un POST, vérifiez avec un GET qu'il n'est pas passé.
Réponse 422
{
    "message": "The selected product type is invalid.",
    "errors": {
        "product_type": [
            "The selected product type is invalid."
        ]
    }
}

Pagination et limites

  • Les listes sont paginées. GET /policies et GET /companies acceptent page et per_page (de 1 à 100, 25 par défaut).
  • Suivez links.next jusqu'à ce qu'il vaille null. meta.total compte tous les enregistrements.
  • 60 requêtes par minute par clé. Une réponse 429 indique le délai d'attente dans Retry-After.
  • JSON uniquement. Envoyez Accept: application/json et, avec un corps, Content-Type: application/json.
GET /policies
{
    "data": [
        "…"
    ],
    "links": {
        "first": "https://freeprivacypolicy.app/api/v1/policies?page=1",
        "last": "https://freeprivacypolicy.app/api/v1/policies?page=3",
        "prev": null,
        "next": "https://freeprivacypolicy.app/api/v1/policies?page=2"
    },
    "meta": {
        "current_page": 1,
        "from": 1,
        "last_page": 3,
        "path": "https://freeprivacypolicy.app/api/v1/policies",
        "per_page": 25,
        "to": 25,
        "total": 61
    }
}

Versionnage et changements

La version figure dans le chemin : /api/v1. Dans la v1, nous ne faisons qu'ajouter des éléments, comme de nouveaux champs, de nouveaux endpoints et de nouveaux services ou sections dans GET /options : ignorez donc les champs que vous ne connaissez pas. Un changement susceptible de casser un client sort sous /api/v2, et la v1 reste active.

  1. 1.0.0, septembre 2026

    Clés personnelles de chaque compte, partagées avec le serveur MCP. Nouveau : GET /me, GET /options, liste et suppression des politiques, company_id et published sur les politiques, et les endpoints des entreprises.