FreePrivacyPolicy

Integra le pagine legali nella tua app

Una sola richiesta scrive informativa sulla privacy, termini di servizio, EULA e standard di sicurezza dei minori e li ospita con una pagina aziendale e app-ads.txt su {slug}.freeprivacypolicy.app. Gratis, senza limiti di informative.

Endpoint
16
Limite di richieste
60/min
Specifica
OpenAPI 3.1

POST /api/v1/policies

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

201 Created, già online

  • pocket-notes.freeprivacypolicy.app/ (Pagina aziendale)
  • pocket-notes.freeprivacypolicy.app/privacy-policy (Informativa sulla privacy)
  • pocket-notes.freeprivacypolicy.app/terms-of-service (Termini di servizio)
  • pocket-notes.freeprivacypolicy.app/end-user-license-agreement (EULA)
  • pocket-notes.freeprivacypolicy.app/child-safety-standards (Standard di sicurezza dei minori)
  • pocket-notes.freeprivacypolicy.app/ads.txt (ads.txt)
  • pocket-notes.freeprivacypolicy.app/app-ads.txt (app-ads.txt)
In questa pagina

Guida rapida

Tre passaggi da zero a un URL dell'informativa sulla privacy da incollare in App Store Connect o Google Play.

  1. Crea un account gratuito

    Informative, aziende e chiave appartengono al tuo account. Nessun piano da scegliere, nessuna carta da aggiungere.

  2. Crea la tua chiave personale

    Apri la pagina dell'assistente e seleziona Crea la mia chiave. Viene mostrata una sola volta, quindi salvala subito, ad esempio come FPP_API_KEY nei secret della CI o nella shell.

    Shell
    export FPP_API_KEY="fpp_your_key_here"
  3. Pubblica la tua prima informativa

    Invia il nome, il tipo di prodotto e il tuo paese. Aggiungi i servizi usati dalla tua app così l'informativa li dichiara.

    Richiesta
    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 risposta contiene tutti gli indirizzi, già online:

    Risposta 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"
            }
        }
    }

Autenticazione

Ogni richiesta porta la tua chiave personale, in uno dei due header. Le richieste senza una chiave valida ricevono 401.

  • Una chiave, due usi. La stessa chiave collega Claude Code e Codex tramite MCP e chiama la REST API.
  • Una nuova chiave sostituisce quella vecchia. Creare una chiave disconnette la precedente ovunque, in un colpo solo.
  • Solo il tuo account. Una chiave legge e modifica solo le tue informative e aziende. I record di altri account rispondono 404.
  • Tienila sul server. Non includere mai la chiave nel binario di un'app o in una pagina web. Chiama l'API dalla CI, da un backend o dal tuo computer.
  • 60 richieste al minuto per chiave. Ogni risposta include X-RateLimit-Remaining.
curl "https://freeprivacypolicy.app/api/v1/me" \
  -H "Authorization: Bearer $FPP_API_KEY" \
  -H "Accept: application/json"

Ricette di integrazione

Flussi pronti da copiare per le attività che gli sviluppatori automatizzano di più. Scegli una lingua una volta e tutti gli esempi della pagina la seguono.

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"

Server MCP su https://freeprivacypolicy.app/mcp

Preferisci chiedere al tuo assistente IA?

La stessa chiave collega Claude Code, Claude Desktop, Codex, Cursor e VS Code. L'assistente legge le tue dipendenze, sceglie i servizi che la tua app usa davvero e chiama questi endpoint per te: pubblicazione, aggiornamento, aziende, app-ads.txt.

Claude Code di Anthropic

Esegui nel terminale
claude mcp add --transport http --scope user freeprivacypolicy https://freeprivacypolicy.app/mcp --header "Authorization: Bearer YOUR_KEY"

Claude Desktop di 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 di OpenAI

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

Cursor di Anysphere

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

Cursor lo installa anche da un link: accedi e collega Cursor per ottenere il tuo con la chiave già inserita.

VS Code di Microsoft · modalità agente di GitHub Copilot

Esegui nel terminale
code --add-mcp '{"name":"freeprivacypolicy","type":"http","url":"https://freeprivacypolicy.app/mcp","headers":{"Authorization":"Bearer YOUR_KEY"}}'

VS Code lo installa anche da un link: accedi e collega VS Code per ottenere il tuo con la chiave già inserita.

Collega un assistente

Riferimento API

Generato dal documento OpenAPI, versione 1.0.0.

URL di 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.

Risposte
  • 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"
Risposta 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.

Risposte
  • 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"
Risposta 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.

Parametri
  • page integer in query

    Page number, starting at 1. Predefinito 1.

  • per_page integer in query

    Items per page, 1 to 100. Predefinito 25.

Risposte
  • 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"
Risposta 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.

Corpo PolicyInput
  • name string obbligatorio

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

  • product_type string obbligatorio

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

    website mobile_app saas game desktop_app browser_extension

  • country string obbligatorio

    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.

    Predefinito "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 valori accettati

    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 valori accettati

    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).

    Predefinito 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.

    Predefinito 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).

    Predefinito "classic".

    classic minimal card

Risposte
  • 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
    }
}'
Corpo della richiesta: Only the required fields
{
    "name": "Pocket Notes",
    "product_type": "mobile_app",
    "country": "Portugal"
}
Risposta 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.

Parametri
  • slug string in path obbligatorio

    The policy slug (its subdomain).

Risposte
  • 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"
Risposta 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.
Parametri
  • slug string in path obbligatorio

    The policy slug (its subdomain).

Corpo 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 valori accettati

    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 valori accettati

    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.

    Predefinito 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).

    Predefinito "classic".

    classic minimal card

Risposte
  • 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"
    ]
}'
Corpo della richiesta: Add a service and a section
{
    "services": [
        "admob",
        "firebase_analytics",
        "revenuecat",
        "openai"
    ],
    "clauses": [
        "accounts",
        "metadata",
        "ai"
    ]
}
Risposta 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.

Parametri
  • slug string in path obbligatorio

    The policy slug (its subdomain).

Risposte
  • 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 non ha corpo.

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.

Parametri
  • slug string in path obbligatorio

    The policy slug (its subdomain).

Corpo
  • app_icon string obbligatorio

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

Risposte
  • 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 non ha corpo.

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.

Parametri
  • slug string in path obbligatorio

    The policy slug (its subdomain).

Risposte
  • 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 non ha corpo.

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.

Parametri
  • page integer in query

    Page number, starting at 1. Predefinito 1.

  • per_page integer in query

    Items per page, 1 to 100. Predefinito 25.

Risposte
  • 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"
Risposta 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.

Corpo CompanyInput
  • company_name string obbligatorio

  • email string obbligatorio

  • 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.

    Predefinito false.

Risposte
  • 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
}'
Corpo della richiesta: 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
}
Risposta 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.

Parametri
  • id integer in path obbligatorio

    The company id.

Risposte
  • 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"
Risposta 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.

Parametri
  • id integer in path obbligatorio

    The company id.

Corpo 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

Risposte
  • 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"
}'
Corpo della richiesta: Replace the app-ads.txt lines
{
    "app_ads_txt": "google.com, pub-1234567890123456, DIRECT, f08c47fec0942fa0\napplovin.com, 0123456789abcdef, DIRECT"
}
Risposta 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.

Parametri
  • id integer in path obbligatorio

    The company id.

Risposte
  • 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 non ha corpo.

Errori

Gli errori sono JSON con un message. Gli errori di validazione aggiungono errors, con chiave per campo.

Stato Quando
401 Non autenticato La chiave manca, è errata, è stata sostituita da una più recente o il suo account è sospeso. Crea una nuova chiave e aggiorna il tuo secret.
404 Non trovato In questo account non esiste nessuna informativa o azienda con quello slug o id. Elenca i tuoi record con GET /policies o GET /companies.
422 Validazione non riuscita Un campo manca o non è valido. errors elenca i messaggi per campo. Verifica le chiavi con GET /options.
429 Troppe richieste Più di 60 richieste in un minuto con la stessa chiave. Attendi i secondi indicati in Retry-After, poi riprova.
5xx Errore del server Qualcosa non ha funzionato da parte nostra. Riprova con un ritardo crescente. Prima di ripetere un POST, verifica con un GET che non sia andato a buon fine.
Risposta 422
{
    "message": "The selected product type is invalid.",
    "errors": {
        "product_type": [
            "The selected product type is invalid."
        ]
    }
}

Paginazione e limiti

  • Gli elenchi sono paginati. GET /policies e GET /companies accettano page e per_page (da 1 a 100, predefinito 25).
  • Segui links.next finché non è null. meta.total conta tutti i record.
  • 60 richieste al minuto per chiave. Un 429 indica quanto attendere in Retry-After.
  • Solo JSON. Invia Accept: application/json e, con un corpo, 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
    }
}

Versionamento e modifiche

La versione è nel percorso: /api/v1. Nella v1 aggiungiamo solo elementi, come nuovi campi, nuovi endpoint e nuovi servizi o sezioni in GET /options, quindi ignora i campi che non conosci. Una modifica che potrebbe rompere un client viene rilasciata come /api/v2, mantenendo attiva la v1.

  1. 1.0.0, settembre 2026

    Chiavi personali di ogni account, condivise con il server MCP. Novità: GET /me, GET /options, elenco ed eliminazione delle informative, company_id e published sulle informative e gli endpoint delle aziende.