{
  "$comment": "Canonical sub-processor list. Served at /sub-processors (HTML) and /sub-processors.json by backend/apps/core/views/sub_processors.py; feeds DPA section 8 / Appendix A and the privacy policy. Baked into the backend image at /assets/legal/ (Dockerfile). Keep in sync with docs/legal/records-of-processing.md section 3. 'added' is the date the entry first appeared on this published list; the list was first published on 2026-09-25, so that date does not say when the provider was first engaged. Values marked 'to be confirmed' are unknown, not asserted: never fill them in from memory.",
  "version": "2026-10-01",
  "last_updated": "2026-10-01",
  "controller": "Scholé Sàrl (EPFL, Bâtiment INF, Station 14, 1015 Lausanne, Switzerland) for customers and learners in Switzerland, the EEA and the United Kingdom; Scholé Inc. (1209 Orange Street, Wilmington, Delaware 19801, USA) for the United States and everywhere else, including Canada, as in Terms of Service section 1",
  "contact": "privacy@schole.ai",
  "notice_period_days": 30,
  "notes": [
    "Transfer basis for US entities is stated as the mechanism we rely on in principle; per-provider DPA and Data Privacy Framework certification status is being verified and filed (see 'to be confirmed').",
    "LLM inference requests routed through OpenRouter may reach only the seven hosts listed under OpenRouter below (settings.OPENROUTER_PROVIDER_ALLOWLIST, PR #3342): every request carries provider.only with that allowlist, data_collection=deny and zdr=true (OpenRouter's Zero Data Retention filter), and the same policy is enforced on the wire for every HTTP client pointed at OpenRouter. The per-host data policy shown below is OpenRouter's published data policy (openrouter.ai/api/frontend/v1/all-providers and /api/v1/endpoints/zdr, read 2026-09-27), not a contractual commitment to Scholé (DPIA R3).",
    "Cardholder data is entered on Stripe-hosted pages and never reaches Schole systems.",
    "MiniMax, StreamLake, SiliconFlow and DekaLLM, Black Forest Labs (FLUX.2 Pro image generation), and the first-party OpenAI and Anthropic endpoints are not on the allowlist and receive no data through OpenRouter (PR #3342, founders' decision of 2026-09-27). FLUX.2 Pro stays off until Black Forest Labs confirms a training opt-out for OpenRouter traffic; lesson illustrations use google/gemini-2.5-flash-image on Google Vertex AI.",
    "Known uncertainty: OpenRouter does not publish which region serves its requests. The Microsoft Azure, Google Vertex AI and Amazon Bedrock slugs also match those companies' global endpoints (any region), and GroqCloud serves from the United States, Helsinki (EU), Canada and Dammam (Saudi Arabia, no adequacy decision). Serving region to be confirmed."
  ],
  "sub_processors": [
    {
      "name": "Microsoft Azure (hosting)",
      "legal_entity": "Microsoft Ireland Operations Ltd",
      "country": "IE",
      "region_of_processing": "Switzerland North (AKS cluster, PostgreSQL, Blob Storage, Front Door, Key Vault, Log Analytics, Video Indexer, AI Search)",
      "purpose": "Platform hosting: application servers, database, file and media storage, edge network, logs and metrics, video indexing and search indexes",
      "data_categories": [
        "All platform data: account and profile data, learning content and conversations, role-play transcripts, uploaded documents, telemetry, backups"
      ],
      "transfer_basis": "Swiss/EU adequacy",
      "added": "2026-09-25",
      "dpa_status": "Microsoft Products and Services DPA (to be confirmed on file)"
    },
    {
      "name": "Microsoft Azure AI (Azure OpenAI, Azure AI Foundry, Document Intelligence)",
      "legal_entity": "Microsoft Corporation",
      "country": "US",
      "region_of_processing": "Azure OpenAI and AI Foundry accounts in East US 2, Central US and Switzerland North; 29 of 30 deployments are GlobalStandard, so inference may run in any Azure region while data at rest stays in the account region. Document Intelligence in West Europe. Two Azure Speech accounts exist (East US and Switzerland North, resource group ScholéAvatar) but no code in the schole_backend repository calls them as of 2026-09-25. Inference region decision pending (issue #3279)",
      "purpose": "AI inference: lesson and chat generation when OpenRouter is disabled or as fallback, embeddings, realtime voice (gpt-realtime), text-to-speech (gpt-4o-mini-tts), Anthropic models via Azure AI Foundry, document text extraction (Document Intelligence)",
      "data_categories": [
        "Conversation content and prompts",
        "Profile-derived context embedded in prompts (role, goals, skills)",
        "Voice audio for realtime sessions",
        "Text of uploaded documents"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "Microsoft Products and Services DPA (to be confirmed on file)"
    },
    {
      "name": "OpenRouter",
      "legal_entity": "OpenRouter, Inc.",
      "country": "US",
      "region_of_processing": "United States (routing); inference by one of the seven allowlisted hosts below, in a region the host chooses (not pinned; see each host)",
      "purpose": "LLM request routing for lesson generation, tutoring chat, role-play voice agents and content authoring (OPENROUTER_ENABLED=true in production)",
      "data_categories": [
        "Conversation content and prompts",
        "Profile-derived context embedded in prompts"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "to be confirmed",
      "routing_policy": "Every OpenRouter inference request carries provider.only = the seven allowlisted hosts below (a caller can narrow the list, never widen it), data_collection=deny and zdr=true, and keeps its preferred order and throughput sort within that list; if no allowed host is left the request fails before it leaves Scholé. The role-play voice path prefers Cerebras, SambaNova, Groq and Nebius. anthropic/claude-fable-5 has no endpoint-level ZDR record on OpenRouter and is sent without zdr, but only to allowlisted hosts that publish no retention. Not enforceable per request, so covered by OpenRouter's account-wide privacy settings (to be set by the account owner): text-to-speech (/audio/speech, whose only host is Google Vertex AI), the knowledge-base sidecar and the web-search plugin.",
      "model_vendors": [
        {
          "name": "OpenAI",
          "models": "gpt-oss-120b, gpt-oss-20b (open weights), gpt-4o, gpt-4o-mini, gpt-5.4, gpt-5.4-mini",
          "served_by": "Microsoft Azure (gpt-4o, gpt-4o-mini, gpt-5.4, gpt-5.4-mini); Cerebras, Groq, SambaNova, Nebius, Amazon Bedrock and Google Vertex AI (gpt-oss). OpenAI's own endpoint is not allowed and receives no data through OpenRouter."
        },
        {
          "name": "Google",
          "models": "gemini-3.5-flash, gemini-2.5-flash (speech-to-text), gemini-2.5-flash-image (lesson illustrations), gemini-3.1-flash-tts-preview",
          "served_by": "Google Vertex AI only; Google AI Studio (retains prompts 55 days) is not allowed."
        },
        {
          "name": "Anthropic",
          "models": "claude-sonnet-4.6, claude-sonnet-5, claude-opus-4.8, claude-fable-5",
          "served_by": "Amazon Bedrock and Google Vertex AI (and Microsoft Azure for claude-fable-5). Anthropic's own endpoint is not allowed and receives no data through OpenRouter."
        }
      ],
      "downstream_providers": [
        {
          "name": "Cerebras",
          "openrouter_slug": "cerebras",
          "role": "inference host for gpt-oss-120b; first choice on the role-play voice path",
          "legal_entity": "Cerebras Systems Inc.",
          "country": "US",
          "region_of_processing": "United States; Cerebras also runs a site in Montreal, Canada (Canada has EU and Swiss adequacy for commercial organisations) and plans one in France; OpenRouter does not state which serves a request",
          "openrouter_data_policy": "No training, no retention, ZDR endpoint",
          "transfer_basis": "Onward transfer by OpenRouter under Scholé's terms with OpenRouter (EU SCCs + UK Addendum + Swiss addendum, to be confirmed) and OpenRouter's terms with the provider; no direct contract between Scholé and this provider; DPF status to be confirmed"
        },
        {
          "name": "Groq",
          "openrouter_slug": "groq",
          "role": "inference host for gpt-oss-120b and gpt-oss-20b; role-play failover",
          "legal_entity": "Groq, Inc.",
          "country": "US",
          "region_of_processing": "Not disclosed (known uncertainty): GroqCloud serves from the United States, Helsinki (EU), Canada and Dammam (Saudi Arabia), and OpenRouter does not publish which region serves its traffic",
          "openrouter_data_policy": "No training, no retention, ZDR endpoint",
          "transfer_basis": "Onward transfer by OpenRouter under Scholé's terms with OpenRouter (EU SCCs + UK Addendum + Swiss addendum, to be confirmed) and OpenRouter's terms with the provider; no direct contract between Scholé and this provider; DPF status to be confirmed; if served from Saudi Arabia, no adequacy decision: SCCs required, to be confirmed",
          "flag": "Serving region not disclosed; may include Saudi Arabia, which has no adequacy decision"
        },
        {
          "name": "SambaNova",
          "openrouter_slug": "sambanova",
          "role": "inference host for gpt-oss-120b; role-play failover",
          "legal_entity": "SambaNova Systems, Inc.",
          "country": "US",
          "region_of_processing": "United States (data centre not stated by OpenRouter)",
          "openrouter_data_policy": "No training, no retention, ZDR endpoint",
          "transfer_basis": "Onward transfer by OpenRouter under Scholé's terms with OpenRouter (EU SCCs + UK Addendum + Swiss addendum, to be confirmed) and OpenRouter's terms with the provider; no direct contract between Scholé and this provider; DPF status to be confirmed"
        },
        {
          "name": "Nebius",
          "openrouter_slug": "nebius",
          "role": "inference host for gpt-oss-120b; role-play failover",
          "legal_entity": "Nebius Group N.V. (Nebius Token Factory)",
          "country": "NL",
          "region_of_processing": "to be confirmed (Nebius operates data centres in Finland, France, Iceland and the United States; OpenRouter does not state which serves this endpoint)",
          "openrouter_data_policy": "No training, no retention, ZDR endpoint",
          "transfer_basis": "EEA entity: Swiss/EU adequacy when served from an EEA data centre; if served from the United States, SCCs required (serving region to be confirmed)"
        },
        {
          "name": "Microsoft Azure (via OpenRouter)",
          "openrouter_slug": "azure",
          "role": "only allowed host for gpt-4o, gpt-4o-mini, gpt-5.4 and gpt-5.4-mini; also a host for claude-fable-5. OpenRouter's own Azure capacity, separate from Scholé's Azure accounts listed above",
          "legal_entity": "Microsoft Corporation",
          "country": "US",
          "region_of_processing": "Any Azure region: the base slug also matches azure/global endpoints; regional endpoints (azure/us, azure/eu, azure/swedencentral) exist for some models",
          "openrouter_data_policy": "No training, no retention, ZDR endpoint",
          "transfer_basis": "Onward transfer by OpenRouter under Scholé's terms with OpenRouter (EU SCCs + UK Addendum + Swiss addendum, to be confirmed) and OpenRouter's terms with the provider; no direct contract between Scholé and this provider; DPF status to be confirmed"
        },
        {
          "name": "Google Vertex AI",
          "openrouter_slug": "google-vertex",
          "role": "host for Gemini models (chat, speech-to-text, lesson illustrations with gemini-2.5-flash-image, text-to-speech) and for Claude and gpt-oss models",
          "legal_entity": "Google LLC",
          "country": "US",
          "region_of_processing": "Any Google region: the base slug also matches google-vertex/global, and gemini-2.5-flash-image has only a global endpoint; regional endpoints (us, eu, europe) exist for some models",
          "openrouter_data_policy": "No training, no retention, ZDR endpoint",
          "transfer_basis": "Onward transfer by OpenRouter under Scholé's terms with OpenRouter (EU SCCs + UK Addendum + Swiss addendum, to be confirmed) and OpenRouter's terms with the provider; no direct contract between Scholé and this provider; DPF status to be confirmed"
        },
        {
          "name": "Amazon Bedrock (AWS, via OpenRouter)",
          "openrouter_slug": "amazon-bedrock",
          "role": "host for Claude models and gpt-oss models. OpenRouter's own Bedrock capacity, separate from the browser-extension AWS account listed below",
          "legal_entity": "Amazon Web Services, Inc.",
          "country": "US",
          "region_of_processing": "Any AWS region: the base slug also matches amazon-bedrock/global cross-region inference; eu-west-1 and US endpoints exist for some models",
          "openrouter_data_policy": "No training, no retention, ZDR endpoint",
          "transfer_basis": "Onward transfer by OpenRouter under Scholé's terms with OpenRouter (EU SCCs + UK Addendum + Swiss addendum, to be confirmed) and OpenRouter's terms with the provider; no direct contract between Scholé and this provider; DPF status to be confirmed"
        }
      ]
    },
    {
      "name": "Groq (direct API)",
      "legal_entity": "Groq, Inc.",
      "country": "US",
      "region_of_processing": "United States",
      "purpose": "Speech-to-text (Whisper large-v3) for chat voice input and role-play voice, called directly at api.groq.com when GROQ_API_KEY is configured; also the OpenAI-compatible fallback endpoint when no Cerebras key is set",
      "data_categories": [
        "Learner voice audio clips",
        "Prompts on the fallback text path"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "to be confirmed"
    },
    {
      "name": "OpenAI (direct API)",
      "legal_entity": "OpenAI, L.L.C.",
      "country": "US",
      "region_of_processing": "United States",
      "purpose": "Speech-to-text fallback (whisper-1) at api.openai.com when the Groq transcription path fails",
      "data_categories": [
        "Learner voice audio clips"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "to be confirmed"
    },
    {
      "name": "Cerebras (direct API)",
      "legal_entity": "Cerebras Systems Inc.",
      "country": "US",
      "region_of_processing": "United States",
      "purpose": "Direct OpenAI-compatible inference endpoint (gpt-oss-120b) for a legacy routing path when CEREBRAS_API_KEY is configured",
      "data_categories": [
        "Prompts and conversation content on that path"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "to be confirmed"
    },
    {
      "name": "Amazon Web Services (browser-extension agent only)",
      "legal_entity": "Amazon Web Services EMEA SARL",
      "country": "LU",
      "region_of_processing": "eu-central-1 (Frankfurt)",
      "purpose": "Amazon Bedrock (Anthropic Claude Haiku) inference, Amazon Transcribe and Amazon Polly for the Ole browser-extension companion agent. Not used by the web platform.",
      "data_categories": [
        "Companion-agent conversation content and page context the learner shares",
        "Voice audio for the extension's voice mode"
      ],
      "transfer_basis": "Swiss/EU adequacy",
      "added": "2026-09-25",
      "dpa_status": "AWS GDPR DPA (to be confirmed on file)"
    },
    {
      "name": "PostHog",
      "legal_entity": "PostHog, Inc.",
      "country": "US",
      "region_of_processing": "EU cloud, Frankfurt (eu.i.posthog.com), project 92916; a separate US-cloud project \"Schole Studies\" serves the pre-test study site (backend/config/settings.py comment; apps/curriculums/services/end_survey.py)",
      "purpose": "Product analytics and in-product surveys; consent-gated for analytics events",
      "data_categories": [
        "Usage events keyed on the profile id",
        "Signup email",
        "AI prompt and response text where the learner has accepted analytics"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "to be confirmed"
    },
    {
      "name": "Sentry",
      "legal_entity": "Functional Software, Inc.",
      "country": "US",
      "region_of_processing": "EU data residency, Frankfurt (ingest.de.sentry.io)",
      "purpose": "Error and performance monitoring for the backend and the web app",
      "data_categories": [
        "Error context: user id, request path, stack traces",
        "IP address and user agent"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "to be confirmed"
    },
    {
      "name": "HubSpot",
      "legal_entity": "HubSpot, Inc.",
      "country": "US",
      "region_of_processing": "United States (data hosting region to be confirmed)",
      "purpose": "CRM, lifecycle and marketing email, support tickets; marketing consent mirrored from ConsentRecord",
      "data_categories": [
        "Name, email, company and role",
        "Lifecycle and marketing consent state",
        "Support conversations"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "to be confirmed"
    },
    {
      "name": "Stripe",
      "legal_entity": "Stripe Payments Europe, Ltd.",
      "country": "IE",
      "region_of_processing": "European Union (Stripe may process in the United States under its own transfer mechanisms)",
      "purpose": "Subscription payments and invoicing. Cardholder data is entered on Stripe-hosted pages and never reaches Schole.",
      "data_categories": [
        "Billing identity: name, email, Stripe customer id",
        "Subscription and invoice records"
      ],
      "transfer_basis": "Swiss/EU adequacy",
      "added": "2026-09-25",
      "dpa_status": "Stripe Data Processing Agreement (to be confirmed on file)"
    },
    {
      "name": "Mercury (bank-transfer invoices)",
      "legal_entity": "Mercury Technologies, Inc.",
      "country": "US",
      "region_of_processing": "United States",
      "purpose": "Invoice creation and payout reconciliation for organizations paying by bank transfer",
      "data_categories": [
        "Organization billing contact name and email"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "to be confirmed"
    },
    {
      "name": "Certifier (credential issuing)",
      "legal_entity": "Certifier sp. z o.o. (Kraków, Poland; KRS 0000863560)",
      "country": "PL",
      "region_of_processing": "AWS, Europe region, according to Certifier's legal and security page (exact AWS region to be confirmed)",
      "purpose": "Hosts the credentials issued before the in-house credential cutover at credsverse.com (Certifier's credential domain); 436 vendor-era credentials stay live there. New issuing through Certifier is off in production (CERTIFIER_ENABLED=False in infra/k8s/overlays/prod/configmap-backend-patch.yaml); badges now issue from Scholé's own verification page",
      "data_categories": [
        "Learner name and email on the legacy credentials",
        "Lesson title and issue date"
      ],
      "transfer_basis": "Intra-EEA (Poland): no third-country transfer from the EEA; Swiss/EU adequacy for Swiss data",
      "added": "2026-09-25",
      "dpa_status": "Certifier DPA (to be confirmed on file)"
    },
    {
      "name": "Google Workspace",
      "legal_entity": "Google LLC",
      "country": "US",
      "region_of_processing": "United States and European Union",
      "purpose": "Company email (transactional mail is sent through the hey@schole.ai mailbox), shared documents and drives, Google sign-in (OAuth)",
      "data_categories": [
        "Email correspondence including data subject requests and support mail",
        "Recipient addresses of transactional email",
        "Google account identifier for learners who sign in with Google"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "Google Cloud / Workspace Data Processing Addendum (to be confirmed on file)"
    },
    {
      "name": "GitHub",
      "legal_entity": "GitHub, Inc.",
      "country": "US",
      "region_of_processing": "United States",
      "purpose": "Source code hosting, CI pipelines, issue tracking and automated review",
      "data_categories": [
        "No learner data by design; incidental personal data in issue text, CI logs and configuration",
        "Staff and contractor accounts"
      ],
      "transfer_basis": "EU SCCs + UK Addendum + Swiss addendum; DPF where certified (to be confirmed)",
      "added": "2026-09-25",
      "dpa_status": "GitHub Data Protection Agreement (to be confirmed on file)"
    },
    {
      "name": "Golpo AI",
      "legal_entity": "Golpo (legal entity to be confirmed)",
      "country": "to be confirmed",
      "region_of_processing": "Not yet confirmed. The code calls api.golpoai.com through the golpo SDK and shows nothing about where Golpo processes or stores data",
      "purpose": "Whiteboard explainer video generation for lesson sections (apps/lesson_lab/services/golpo.py): the section is uploaded as a JSON file and Golpo returns a narrated video and its script. Used for customer-authored lessons in Lesson Lab when an author asks for a video, and for Scholé's own lessons. The video is served from the URL Golpo returns",
      "data_categories": [
        "Lesson section text sent for each video (title, description, subsections, learning goals); for customer-authored lessons this is customer content, with personal data only where an author put it in the lesson",
        "The generated narration script and video"
      ],
      "transfer_basis": "To be confirmed once Golpo's location and processing region are known; EU SCCs + UK Addendum + Swiss addendum if outside an adequacy decision",
      "added": "2026-10-01",
      "dpa_status": "to be confirmed"
    }
  ],
  "internal_systems": [
    {
      "name": "Langfuse (LLM tracing, being removed, PR #3325)",
      "hosting": "Self-hosted on the nonprod AKS cluster, Switzerland North (langfuse.dev.schole.ai), and receives production traces. Being removed entirely (issue #3280, PR #3325)",
      "purpose": "Traces of LLM calls for debugging and quality review",
      "data_categories": [
        "Prompts and model responses",
        "Internal user and conversation identifiers"
      ],
      "why_not_a_sub_processor": "Runs on Schole-controlled infrastructure; no third party receives the data."
    }
  ]
}