Samio
v1.0.0
OAuth 2.0
NL GOV Profile

Riferimento API Edu-V

Documentazione di integrazione per l'interoperabilità educativa olandese

URL base: https://api.samiolearning.com/v1/eduv
Gruppo target: Istruzione primaria (primair onderwijs / po)
Specifica: Edu-V v1.0 (Stichting Edu-V)

Panoramica

Samio partecipa a Edu-V (release NR26) come dashboard di progresso per gli insegnanti. È afnemer (consumatore) di dati di amministrazione scolastica — onderwijsinrichting, onderwijsdeelnemers, onderwijsmedewerkers e gruppi — dai SIS olandesi come ParnasSys ed ESIS, e verzender (mittente) dei risultati di apprendimento prodotti nell'app gratuita per alunni di Samio. Samio non è un portale: non riceve diritti, dati di catalogo né risultati.

Ruoli di Samio

ReferentiecomponentGegevensdienstDirezioneRelease
Dienst met SSOIdentiteitsverklaringDestinatario (ontvanger)NR26
Dashboard voortgangOnderwijsinrichtingConsumatore (afnemer)NR26
Dashboard voortgangOnderwijsdeelnemerConsumatore (afnemer)NR26
Dashboard voortgangOnderwijsmedewerkersConsumatore (afnemer)NR26
Dashboard voortgangOnderwijsdeelname (groepen)Consumatore (afnemer)NR26
Dashboard voortgangLeerresultatenMittente (verzender)NR26
text
Inbound — koppelvlakken Samio exposes
/v1/eduv/
├── .well-known/      # OAuth metadata + participation statement
├── oauth/            # Token endpoint + JWKS
├── consent/          # Consent lifecycle (supporting)
├── dpa/              # DPA verification (supporting)
└── notifications/    # Roster-change notifications (we subscribe)

Outbound — koppelvlakken Samio calls at the partner
├── GET  {sis}/education|students|employees|groups   # afnemer
└── POST {receiver}/results                          # verzender

Autenticazione

Tutti gli endpoint richiedono un token Bearer ottenuto tramite OAuth 2.0 con il profilo NL GOV (autenticazione client private_key_jwt).

Endpoint token

POST/v1/eduv/oauth/token
Corpo della richiesta
ParametroTipoDescrizione
grant_typestring
Obbligatorio
Must be "client_credentials"
client_assertion_typestring
Obbligatorio
urn:ietf:params:oauth:client-assertion-type:jwt-bearer
client_assertionstring
Obbligatorio
Signed JWT (RS256, PKIoverheid key)
scopestring
Opzionale
Space-separated scopes
bash
curl -X POST https://api.samiolearning.com/v1/eduv/oauth/token \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "grant_type=client_credentials" \
  -d "client_assertion_type=urn:ietf:params:oauth:client-assertion-type:jwt-bearer" \
  -d "client_assertion=eyJhbGciOiJSUzI1NiIs..." \
  -d "scope=eduv.student.read eduv.association"
json
{
  "access_token": "eyJhbGciOiJSUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 3600,
  "scope": "eduv.student.read eduv.association"
}

Endpoint JWKS

GET/v1/eduv/oauth/.well-known/jwks.json

Token Properties

Algorithm:RS256Durata del token:3600 secondiIssuer:https://api.samiolearning.comAudience:https://api.samiolearning.com/v1/eduv

Codici di errore

json
{
  "error": "Human-readable error message",
  "error_code": "1001",
  "error_description": "Optional additional details"
}
CodiceStato HTTPMessaggio
0021
401
Not authorized for this scope
0011
400
Schema validation failed
0012
400
schemaVersion not supported
0022
403
Consent required for this data service
0023
400
Unknown education organisation
0099
400
Other rejection (reason in statusMessage)
0099
500
Internal server error

Paginazione

Gli endpoint paginati accettano i parametri start e limit.

ParametroTipoPredefinitoMax
startinteger0
limitinteger20100
json
{
  "data": [ ... ],
  "total": 142,
  "start": 0,
  "limit": 20,
  "hasMore": true
}

DPA

In entrata — Samio lo espone
eduv.dpa
GET/v1/eduv/dpa/agreements

Get DPA agreement status for a school.

Parametri
ParametroTipoDescrizione
schoolBrinCodestring
Obbligatorio
School's BRIN code
POST/v1/eduv/dpa/verify

Verify a Data Processing Agreement (verwerkersovereenkomst).

Corpo della richiesta
ParametroTipoDescrizione
schoolBrinCodestring
Obbligatorio
School's BRIN code
dpaReferencestring
Opzionale
Agreement reference number
agreementDateISO date
Opzionale
Date of agreement

Risposta

json
{
  "verified": true,
  "partner": { "oin": "0000000123...", "name": "ParnasSys" },
  "schoolBrinCode": "01AB",
  "verificationType": "local"
}

Istruzione

In uscita — Samio lo chiama sul tuo endpoint
eduv.education
GET/v1/eduv/education/organisations

List schools with Edu-V enabled.

Parametri
ParametroTipoDescrizione
brinCodestring
Opzionale
Filter by BRIN code
startinteger
Opzionale
Pagination offset
limitinteger
Opzionale
Page size (max 100)
GET/v1/eduv/education/organisations/:id

Get a specific organisation by ID.

GET/v1/eduv/education/study-offerings

List study offerings (grades). Maps to Groep 1-8.

Parametri
ParametroTipoDescrizione
schoolIdstring
Obbligatorio
School ObjectId
GET/v1/eduv/education/subject-offerings

List subject offerings. Maps Samio modules to Edu-V subjects.

Parametri
ParametroTipoDescrizione
schoolIdstring
Obbligatorio
School ObjectId

Studenti

In uscita — Samio lo chiama sul tuo endpoint
eduv.student.read
Consenso richiesto: eduv.student.read
GET/v1/eduv/students

List students for a school. Consent required.

Parametri
ParametroTipoDescrizione
schoolIdstring
Obbligatorio
School ObjectId
classGroupIdstring
Opzionale
Filter by class group
eckIdstring
Opzionale
Filter by ECK iD
startinteger
Opzionale
Pagination offset
limitinteger
Opzionale
Page size (max 100)
GET/v1/eduv/students/:eckId

Get a single student by ECK iD.

Dipendenti

In uscita — Samio lo chiama sul tuo endpoint
eduv.employee.read
Consenso richiesto: eduv.employee.read
GET/v1/eduv/employees

List employees for a school. Consent required.

Parametri
ParametroTipoDescrizione
schoolIdstring
Obbligatorio
School ObjectId
rolestring
Opzionale
Filter: owner, admin, teacher
startinteger
Opzionale
Pagination offset
limitinteger
Opzionale
Page size (max 100)
GET/v1/eduv/employees/:id

Get a single employee by ID.

Associazione

In uscita — Samio lo chiama sul tuo endpoint
eduv.association
Consenso richiesto: eduv.association
GET/v1/eduv/association/groups

List class groups for a school.

Parametri
ParametroTipoDescrizione
schoolIdstring
Obbligatorio
School ObjectId
GET/v1/eduv/association/groups/:groupId/students

List students in a specific class group.

GET/v1/eduv/association/enrollments

List enrollments linking students to studies and groups.

Parametri
ParametroTipoDescrizione
schoolIdstring
Obbligatorio
School ObjectId
eckIdstring
Opzionale
Filter by student ECK iD

Risultati

In uscita — Samio lo chiama sul tuo endpoint
eduv.result
GET/v1/eduv/results

Get learning results for students.

Parametri
ParametroTipoDescrizione
schoolIdstring
Opzionale
Filter by school
eckIdstring
Opzionale
Filter by ECK iD
sinceISO date
Opzionale
Results after this date
exerciseTypestring
Opzionale
math, reading, grammar, clock, science, physics
GET/v1/eduv/results/summary

Aggregated per-student learning summary.

Parametri
ParametroTipoDescrizione
schoolIdstring
Opzionale
Filter by school
eckIdstring
Opzionale
Filter by student
sinceISO date
Opzionale
Default: 30 days ago

Notifiche

In entrata — Samio lo espone
eduv.notifications
POST/v1/eduv/notifications/subscribe

Subscribe to change notifications (webhooks).

Corpo della richiesta
ParametroTipoDescrizione
callbackUrlstring
Obbligatorio
URL to receive webhooks
notificationTypesstring[]
Obbligatorio
Event types to subscribe to
schoolIdstring
Opzionale
Scope to specific school
DELETE/v1/eduv/notifications/subscribe/:id

Unsubscribe from notifications.

GET/v1/eduv/notifications/subscriptions

List active subscriptions.

POST/v1/eduv/notifications/receive

Receive inbound notification from a partner (webhook).

Corpo della richiesta
ParametroTipoDescrizione
notificationTypestring
Obbligatorio
Event type
objectTypestring
Obbligatorio
student, employee, group, etc.
objectIdstring
Opzionale
Object identifier
schoolobject
Opzionale
{ brinCode }
urlstring
Opzionale
URL to fetch the updated object
isDeleteNotificationboolean
Opzionale
Whether the object was deleted

Scopes

Scopes OAuth 2.0 disponibili per l'integrazione Edu-V.

ScopeAPIDescrizione
eduv.consentConsentManage consent lifecycle (supporting)
eduv.dpaDPAVerify Data Processing Agreements (supporting)
eduv.notificationsNotificationsSubscribe to roster-change notifications
eduv.educationEducationOnderwijsinrichting — organisations, studies, subjects (afnemer)
eduv.student.basicStudentsOnderwijsdeelnemer — identity and name (afnemer)
eduv.employee.basicEmployeesOnderwijsmedewerkers — identity and name (afnemer)
eduv.associationAssociationOnderwijsdeelname — groups and enrollments (afnemer)
eduv.resultResultsLeerresultaten — results sent by Samio (verzender)

Modelli dati

CampoTipoDescrizione
schoolIdObjectId → SchoolTarget school
partnerIdObjectId → EduVPartnerPartner
dataServicestringEdu-V scope
statusenumrequested | granted | revoked | denied
initiatedByenumschool | partner
grantedAtDateWhen consent was granted
expiresAtDateConsent expiry
CampoTipoDescrizione
entitlementIdstringUnique ID
productIdstringProduct reference
schoolIdObjectId → SchoolSchool
eckIdstringStudent ECK iD
entitlementTypeenumDelivery type
statusenumcreated → entitled → licensed → activated / cancelled / blocked / expired
licensePeriodobject{ start, end }
activationCodestringIf activated by code
CampoTipoDescrizione
eduv.brinCodestringBRIN school identifier
eduv.oaIdstringOnderwijsaanbieder ID
eduv.oinNumberstringOIN
eduv.boardIdstringBestuur ID
eduv.bestuursnummerstringBoard number
eduv.enabledbooleanWhether Edu-V is active
CampoTipoDescrizione
eduv.eckIdstringECK iD — primary Dutch student identifier
eduv.givenNamestringFirst name
eduv.familyNamestringLast name
eduv.familyNamePrefixstringTussenvoegsel ("van", "de")
eduv.externalIdsarray[{ type, value }]

Avvio rapido

Flusso di integrazione completo dalla registrazione del partner alla lettura dei risultati.

1

Partner registers with Samio → EduVPartner record created

2

Partner obtains token → POST /v1/eduv/oauth/token

3

Partner requests consent → POST /v1/eduv/consent/request

4

School grants consent → POST /v1/eduv/consent/:id/confirm

5

Partner reads students → GET /v1/eduv/students?schoolId=...

6

Partner places order → POST /v1/eduv/orders

7

Samio creates entitlement → POST /v1/eduv/entitlement (internal)

8

Partner activates → POST /v1/eduv/activation-codes/request

9

Student uses Samio → (normal app usage)

10

Partner reads usage → GET /v1/eduv/usage/entitlements

11

Partner reads results → GET /v1/eduv/results?eckId=...

Strumenti per agenti (WebMCP)

Experimental
navigator.modelContext
read-only on public pages
teacher tools on the dashboard

Strumenti che gli agenti IA nel browser possono richiamare su samiolearning.com: quattro di sola lettura su ogni pagina pubblica (prezzi per paese, ricerca pagine, dati di prodotto, link delle app) e, per un insegnante autenticato nella dashboard scolastica, gli stessi dodici strumenti per insegnanti del server MCP, eseguiti con la sessione dell'insegnante.

WebMCP is the W3C-incubated standard (Google + Microsoft) that lets a web page register tools an AI agent running in the browser can call — the page-side counterpart of an MCP server. Every public page on samiolearning.com registers the four tools below once the page has loaded, in browsers that exposenavigator.modelContext. Other browsers pay nothing: the module is loaded at idle and only when the API exists. The tools are deliberately read-only. Nothing submits a form, starts a trial or touches payment; an agent that wants to register a school must hand the person the registration page.

samio_get_pricing_for_countryGET /v1/schools/pricing/resolve (public) · static tier table as fallback

Samio for Schools price for a country: equity-pricing tier (World Bank income group), discount, and the monthly USD price of the Homeschool, Classroom and School plans.

InputTypeRequiredDescription
countrystringyesISO 3166-1 alpha-2 code, e.g. NL, MX, IN

Returns

json
{
  "country": "MX",
  "pricingTier": "tier_b",
  "pricingTierLabel": "Equity — Upper-middle income",
  "discountPercent": 50,
  "currency": "USD",
  "billing": "monthly via PayPal; every plan starts with a 14-day free trial",
  "plans": [
    { "id": "homeschool", "priceUsdPerMonth": 2.49, "standardPriceUsdPerMonth": 4.99, "limits": { "students": 10, "teachers": 1, "classes": 1 } },
    { "id": "classroom",  "priceUsdPerMonth": 9.0,  "standardPriceUsdPerMonth": 19.0, "limits": { "students": 60, "teachers": 1, "classes": 4 } },
    { "id": "school",     "priceUsdPerMonth": 79.0, "standardPriceUsdPerMonth": 159.0, "limits": { "students": 1500, "teachers": "unlimited", "classes": "unlimited" } }
  ],
  "resolvedBy": "api",
  "explanation": "https://samiolearning.com/schools/equity-pricing",
  "register": "https://samiolearning.com/schools/register"
}
samio_find_pagein-page index of public routes

Find the samiolearning.com page that answers a question. Returns up to 5 URLs with titles and descriptions, localized to the requested language where a translation exists.

InputTypeRequiredDescription
querystringyesFree-text question or keywords
languagestringnoen (default), es, nl, de, fr, it, pt
audiencestringnoparents | schools | developers

Returns

json
{
  "query": "how do i connect google classroom",
  "results": [
    { "title": "Plug Samio into your LMS in 10 minutes", "url": "https://samiolearning.com/schools/integrations", "audience": "schools", "relevance": 7, "description": "…" }
  ]
}
samio_get_product_factsGET /facts.json

Canonical facts about Samio Learning, Samio for Schools or Askimo (features, platforms, compliance, pricing, comparisons) plus entity disambiguation for the names "Samio" and "Askimo".

InputTypeRequiredDescription
productstringnosamio | schools | askimo — omit for all three

Returns

json
{ "products": [ { "name": "Askimo", "category": "Free educational Wikipedia app for kids ages 4–12", "…": "…" } ], "entityDisambiguation": { "samio": "…", "askimo": "…" }, "source": "https://samiolearning.com/facts.json" }
samio_get_app_linksstatic

Official App Store, Google Play and web links for the Askimo or Samio Learning apps, with price and age range.

InputTypeRequiredDescription
appstringnoaskimo (default) | samio

Returns

json
{ "app": "Askimo", "appStore": "https://apps.apple.com/app/askimo/id6760259046", "googlePlay": "…", "web": "https://samiolearning.com/askimo", "price": "Free, no ads, no accounts", "ages": "4–12", "languages": ["en","es","nl","de","fr","it","pt"] }

Dashboard tools for signed-in teachers

On /schools/dashboard/*, and only while a teacher is signed in, the page additionally registers the twelve teacher tools of the remote MCP server — same names, same input schemas — so a browser agent (Chrome, Gemini in Chrome, Edge Copilot) can do the same work without OAuth: every call runs through the dashboard's own endpoints with the teacher's session, under the same plan limits and consent checks as a click in the UI. The set is withdrawn on logout or when leaving the dashboard; public pages never see it. Generation tools return the new id with status: "generating" and the matching get_ tool polls, exactly as on the MCP server. The schemas are published in the manifest under dashboardTools.

list_my_classeslist_material_typesgenerate_teaching_materialget_teaching_materiallist_teaching_materialscreate_topic_planget_topic_planget_topic_plan_weeklist_topic_plansgenerate_challengesearch_knowledge_factsget_class_curriculum_progress

Discovery and testing

  • Static manifest of the same tools: /agent-tools.json. Plain-text brief for LLMs: /llms.txt; machine-readable facts: /facts.json.
  • In a WebMCP-capable browser (Chrome early preview; enable the WebMCP flag in chrome://flags), open any samiolearning.com page and the tools appear in the browser's agent tool list after load.
  • Non-browser agents (an MCP server, a script) do not need WebMCP: the two network-backed tools wrap plain HTTP endpoints you can call directly, shown below.
http
# Country → pricing tier (public, no auth)
GET https://api.samiolearning.com/v1/schools/pricing/resolve?country=MX
→ { "success": true, "data": { "country": "MX", "pricingTier": "tier_b", "pricingTierLabel": "Equity — Upper-middle income", "pricingDiscountPercent": 50, "currency": "USD" } }

# Canonical product facts
GET https://samiolearning.com/facts.json

# Tool manifest
GET https://samiolearning.com/agent-tools.json

Status: the WebMCP API surface is still changing. The page registers with whichever ofregisterTool() orprovideContext() the browser exposes and silently skips registration otherwise. Tool names and schemas are stable; report problems to info@samiolearning.com.

Server MCP remoto (Samio per le Scuole)

v1
MCP 2026-07-28
Streamable HTTP
no login for curriculum tools
OAuth 2.1 for teacher tools
no student data

Un server MCP remoto a cui può collegarsi qualsiasi assistente IA — Claude, ChatGPT, Gemini, Claude Code o il tuo agente. Quattro strumenti di sola lettura sui curricoli ufficiali della scuola primaria in oltre 60 paesi e i prezzi di Samio per le Scuole funzionano senza login; tredici strumenti per insegnanti (materiali, piani tematici, sfide, fatti verificati, copertura per classe) si attivano quando un insegnante collega il proprio account Samio per le Scuole con OAuth 2.1. Nessun dato degli alunni, in nessuno strumento.

Endpoint: https://mcp.samiolearning.com/mcp
Health: https://mcp.samiolearning.com/health

The server speaks the Model Context Protocol over Streamable HTTP and is stateless: every request carries what it needs, so it works with any current MCP client. The server lists seventeen tools. The four below need no account: they read the same curriculum spine that grounds every exercise in Samio (60+ countries, seven interface languages) and the public pricing resolver. The other fourteen are teacher tools: they become usable once a teacher connects their Samio for Schools account with OAuth 2.1 and act only inside that teacher's own classes. No tool on either tier returns a student name, score or result, and the gateway behind the server stores only hashed inputs and salted IP hashes for abuse control.

list_countries_grades_subjectsList curriculum coverageGET /v1/agent/curriculum/countries

Which countries, grades (Samio stages 1–7 with age ranges) and subjects Samio holds official national-curriculum data for. Call this first when unsure of codes.

InputTypeRequiredDescription
countrystringnoOptional ISO country code (e.g. NL, ES, US) to return one country only

Returns

json
{
  "countries": [
    { "country": "NL", "language": "nl",
      "grades": [ { "gradeLevel": 1, "gradeName": "Groep 3", "ageRange": { "min": 6, "max": 7 } }, … ],
      "subjects": ["math", "reading", "grammar", "science", "physics", "computing"] },
    …
  ]
}
search_curriculum_standardsSearch curriculum standardsGET /v1/agent/curriculum/standards

Official national-curriculum units, skills, competencies and assessment criteria for a country + subject + grade (or age), optionally ranked by a topic query. Returns standardId/unitId for follow-up calls.

InputTypeRequiredDescription
countrystringyesISO country code, e.g. NL, ES, DE, FR, IT, PT, GB, US
subjectenumyesmath | reading | grammar | clock | science | physics | history | computing
gradeinteger 1–7noSamio stage (1 ≈ age 4–5 … 7 ≈ age 11–13). Give grade OR age
ageinteger 3–18noChild's age; the matching grade is chosen for you
languagestringnoLanguage of the curriculum text (defaults to the country's)
querystring ≤120noFree-text topic to rank units by, e.g. 'fractions', 'breuken'
limitinteger 1–50noMax units to return (default 20)

Returns

json
{
  "standard": { "standardId": "…", "country": "NL", "language": "nl", "gradeLevel": 1, "gradeName": "Groep 3",
                "ageRange": { "min": 6, "max": 7 }, "subject": "math",
                "officialName": "Rekenen/Wiskunde — Kerndoelen 23–33 (SLO)",
                "source": { "name": "SLO Kerndoelen Primair Onderwijs", "url": "https://www.slo.nl/…" },
                "assessmentFocus": "Automatiseren van optellen en aftrekken tot 10" },
  "units": [ { "unitId": "NL:math:g1:u:rrw96f", "name": "Optellen en aftrekken tot 20", "description": "…",
               "skills": [ { "skillId": "NL:math:g1:s:lm8mtk", "name": "Sommen tot 10" } ], "matchScore": 0 } ],
  "competencies": [ { "competencyId": "…", "name": "Getalbegrip en getalrelaties" } ],
  "criteria": [ { "criterionId": "…", "text": "Leerlingen kunnen getallen tot 20 lezen, schrijven en ordenen", "area": "comprehension" } ]
}
get_curriculum_unitGet one curriculum unitGET /v1/agent/curriculum/units/:unitId?standardId=

Full detail of one curriculum unit (skills) plus the standard's competencies and assessment criteria.

InputTypeRequiredDescription
standardIdstringyesstandardId from search_curriculum_standards
unitIdstringyesunitId from search_curriculum_standards

Returns

json
{ "standard": { … }, "unit": { "unitId": "…", "name": "…", "description": "…", "skills": [ … ] }, "competencies": [ … ], "criteria": [ … ] }
get_pricing_for_countryGet Samio for Schools pricingGET /v1/agent/pricing?country=XX (same JSON as /v1/schools/pricing/resolve)

Plan prices, purchasing-power tier and limits for a school in a given country.

InputTypeRequiredDescription
countrystringyesTwo-letter ISO country code of the school, e.g. MX, NL, US

Returns

json
{ "success": true, "data": { "country": "MX", "countrySource": "query", "pricingTier": "tier_b", "pricingTierLabel": "Equity — Upper-middle income", "pricingDiscountPercent": 50, "currency": "USD" } }

Connect it

  • Claude (claude.ai, Desktop, mobile, Cowork): Customize → Connectors → Add custom connector → paste the endpoint, authentication “none”. On Team and Enterprise plans an Owner adds it once for the organisation.
  • ChatGPT: Settings → Connectors → Create (developer mode) → paste the endpoint, no authentication.
  • Claude Code, Gemini CLI, the Claude API and any other MCP client: snippets below. Listings in the Claude Connectors Directory and the ChatGPT plugin directory are being prepared; until they are live the custom-connector route above is the way in.
  • Teachers: the non-technical walkthrough with example prompts is the announcement article Samio for Schools now works inside Claude and ChatGPT.
bash
# Claude Code
claude mcp add --transport http samio https://mcp.samiolearning.com/mcp

# Gemini CLI — ~/.gemini/settings.json
{ "mcpServers": { "samio": { "httpUrl": "https://mcp.samiolearning.com/mcp", "oauth": { "enabled": true } } } }

# Any MCP client / plain HTTP: list the tools (JSON-RPC over Streamable HTTP)
curl -s https://mcp.samiolearning.com/mcp \
  -H 'Content-Type: application/json' -H 'Accept: application/json, text/event-stream' \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}'
http
# Claude API — let the model call the server directly (MCP connector, beta)
POST https://api.anthropic.com/v1/messages
anthropic-beta: mcp-client-2025-11-20
{
  "model": "claude-opus-5",
  "max_tokens": 1024,
  "mcp_servers": [ { "type": "url", "url": "https://mcp.samiolearning.com/mcp", "name": "samio" } ],
  "tools": [ { "type": "mcp_toolset", "mcp_server_name": "samio" } ],
  "messages": [ { "role": "user", "content": "What does the Dutch curriculum expect in maths for a 7-year-old?" } ]
}

Strumenti per insegnanti (OAuth 2.1)

authorization code + PKCE S256
refresh rotation
CIMD or DCR
no client_credentials
no student data

Teachers can connect their Samio for Schools account to Claude, ChatGPT or any MCP client and let the assistant create teaching materials, topic plans and challenges in their own classes, read Samio's verified knowledge facts and see class-level curriculum coverage. The connection is an ordinary OAuth 2.1 grant: the teacher signs in with the same credentials as the dashboard, sees exactly which permissions the app asks for, and can revoke the app at any time under Settings → Connected apps. Generation runs on the same queues, plan limits and consent checks as the dashboard, and every generated artefact carries a provenance line naming the app.

How a teacher connects

  1. 1Connect. Add https://mcp.samiolearning.com/mcp in Claude (Customize → Connectors) or ChatGPT (Settings → Connectors). The curriculum tools work right away; the first teacher tool call answers 401 with the resource metadata, which makes the client start the login.
  2. 2Samio login. The browser opens samiolearning.com/oauth/consent. The teacher signs in with their school account — e-mail and password, Google, Microsoft or the school's SSO — exactly as on the dashboard.
  3. 3Approve permissions. The consent screen names the app and its publisher, the school and the signed-in teacher, and lists the requested scopes in the teacher's language, with the fixed line "This app never receives student names, scores or results." Approve or Deny.
  4. 4Tools appear. The client exchanges the code for a one-hour access token (plus a rotating 30-day refresh token) and the fourteen teacher tools are live. Revoking under Settings → Connected apps cuts them off within seconds.

Scopes

Space-separated in scope. Every consent grants at least openid email; a request without scopes is treated as openid email classes:read. The titles below are the ones the teacher sees on the consent screen (in all seven interface languages). students:read is reserved and never issued.

ScopeWhat the teacher readsTools
openid emailKnow who you areName and e-mail of the connected teacher (OIDC id_token + userinfo). Always granted.get_my_account
classes:readSee your classesClass names and student counts, never student names.list_my_classes
materials:writeCreate teaching materials in your accountMind maps, presentations, didactic materials, study cards.list_material_types, generate_teaching_material, get_teaching_material, list_teaching_materials
plans:writeCreate topic plans and lessons for your classesCurriculum-grounded plans on the school's academic calendar.create_topic_plan, get_topic_plan, get_topic_plan_week, list_topic_plans
challenges:writeCreate challengesDrafts unless the teacher asks to publish.generate_challenge
knowledge:readRead Samio's verified knowledge factsSourced facts that ground generated content.search_knowledge_facts
analytics:readSee class-level curriculum coverageNever per-student results.get_class_curriculum_progress

The fourteen teacher tools

Every Tier B call sends Authorization: Bearer <access token> to the gateway; a missing or expired token answers 401 with WWW-Authenticate: Bearer resource_metadata=…, a missing scope 403 AGENT_SCOPE_MISSING (with the required scope), a revoked connection 403 AGENT_GRANT_REVOKED. Generation tools are asynchronous: they return the new id with status: "generating" and the matching get_ tool polls (typically 1–5 minutes). Per-school generation quota: 50 calls per day (429 AGENT_SCHOOL_QUOTA_EXCEEDED + Retry-After); a subscription limit answers 402 PLAN_LIMIT_REACHED.

get_my_accountWho am I
any
GET /v1/agent/me

The connected teacher, their school and the scopes this connection holds. Call it first to confirm which account the assistant is acting for.

InputTypeRequiredDescription
No input.

Returns

json
{ "user": { "id": "…", "name": "Ana Ruiz", "email": "ana@school.example", "role": "teacher" },
  "school": { "id": "…", "name": "Colegio Sol", "country": "ES", "language": "es", "plan": "school" },
  "scopes": ["openid", "email", "classes:read", "materials:write"], "app": { "name": "Claude" } }
list_my_classesList my classes
classes:read
GET /v1/agent/classes

Your classes with id, name, grade, subjects, language and student count — never student names. The classId feeds every other tool.

InputTypeRequiredDescription
No input.

Returns

json
{ "classes": [ { "classId": "…", "name": "3º A", "gradeLevel": 3, "gradeName": "3.º de Primaria", "subjects": ["math", "reading", …], "language": "es", "studentCount": 24, "academicCalendarId": "…" } ] }
list_material_typesList material types
materials:write
GET /v1/agent/material-types

The four material types Samio generates, with a description of each.

InputTypeRequiredDescription
No input.

Returns

json
{ "types": [ { "type": "mindmap", "title": "Mind map", "description": "…" }, { "type": "presentation", … }, { "type": "didactic_material", … }, { "type": "study_cards", … } ] }
generate_teaching_materialGenerate a teaching material
materials:write
async
POST /v1/agent/teaching-materials → 202

Start generating a material on a topic for a class (or a subject + grade). Same validation, plan limits and queue as the dashboard.

Asynchronous — poll get_teaching_material until status is "ready" (typically 1–5 minutes).

InputTypeRequiredDescription
materialTypeenumyesmindmap | presentation | didactic_material | study_cards
topicstring 2–200yesTopic of the material
classIdstringnoClass to create it for — give classId OR subject + gradeLevel
subjectenumnomath | reading | grammar | clock | science | physics | history | computing
gradeLevelinteger 1–7noSamio stage when no classId is given
languagestringnoContent language (defaults to the school's)
unitIdstringnoCurriculum unit to ground on (from search_curriculum_standards)
standardIdstringnoStandard the unit belongs to
optionsobjectnoType-specific: slideCount + theme, branches, cardCount, materialKind + includeAnswerKey, includeImages

Returns

json
{ "materialId": "…", "status": "generating", "title": "Fractions — mind map", "materialType": "mindmap", "provenance": "Created with Samio's AI assistant via Claude" }
get_teaching_materialGet a teaching material
materials:write
GET /v1/agent/teaching-materials/:materialId

Status and, once ready, the stored content of one material (markdown or structured JSON, as the dashboard receives it).

InputTypeRequiredDescription
materialIdstringyesFrom generate_teaching_material or list_teaching_materials

Returns

json
{ "materialId": "…", "status": "ready", "title": "…", "materialType": "presentation", "subject": "science", "classId": "…", "content": { … }, "provenance": "…", "dashboardUrl": "https://samiolearning.com/schools/dashboard/teaching-materials" }
list_teaching_materialsList teaching materials
materials:write
GET /v1/agent/teaching-materials?classId&limit

Your materials, newest first (max 50), optionally for one class.

InputTypeRequiredDescription
classIdstringnoOnly this class
limitinteger 1–50noDefault 20

Returns

json
{ "materials": [ { "materialId": "…", "status": "ready", "title": "…", "materialType": "study_cards", "createdAt": "2026-09-21T09:12:00Z" } ] }
create_topic_planCreate a topic plan
plans:write
async
POST /v1/agent/topic-plans → 202

Start a curriculum-grounded plan for a class and subject on the school's active academic calendar. mode "auto" also generates lessons and challenges for every week.

Asynchronous — poll get_topic_plan; its progress block reports the phase and percentage (typically 1–5 minutes, longer for "auto").

InputTypeRequiredDescription
classIdstringyesClass
subjectenumyesmath | reading | grammar | clock | science | physics | history | computing
modeenumnoplan (default) | auto
weeksinteger 1–52noAdvisory — the academic calendar sets the real span
classProfileobjectno{ studentCount, energyLevel: calm | balanced | energetic, traits[], notes }
languagestringnoContent language

Returns

json
{ "planId": "…", "status": "generating", "mode": "plan", "title": "Matemáticas 3º A 2026–2027", "provenance": "…" }
get_topic_planGet a topic plan
plans:write
GET /v1/agent/topic-plans/:planId

Status, progress and the week list of one plan.

InputTypeRequiredDescription
planIdstringyesFrom create_topic_plan or list_topic_plans

Returns

json
{ "planId": "…", "status": "active", "mode": "plan", "title": "…", "subject": "math", "classId": "…", "totalWeeks": 36,
  "progress": { "phase": "weeks", "percent": 100, "message": "Done" },
  "weeks": [ { "weekNumber": 1, "title": "Numbers to 1000", "topics": ["Place value", "Comparing"], "status": "pending", "hasLesson": true, "materialIds": [], "challengeIds": [] } ],
  "dashboardUrl": "https://samiolearning.com/schools/dashboard/topic-planner?view=detail&planId=…" }
get_topic_plan_weekGet one week of a plan
plans:write
GET /v1/agent/topic-plans/:planId/weeks/:weekNumber

Topics, objectives, the lesson (when generated) and the materials and challenges linked to one week.

InputTypeRequiredDescription
planIdstringyesPlan
weekNumberinteger ≥ 1yes1-based week

Returns

json
{ "planId": "…", "weekNumber": 3, "title": "…", "topics": [ … ], "objectives": [ … ], "lesson": { … } | null,
  "materials": [ { "materialId": "…", "title": "…", "materialType": "mindmap", "status": "ready" } ],
  "challenges": [ { "challengeId": "…", "title": "…", "status": "draft" } ] }
list_topic_plansList topic plans
plans:write
GET /v1/agent/topic-plans?classId

Your plans, optionally for one class.

InputTypeRequiredDescription
classIdstringnoOnly this class

Returns

json
{ "plans": [ { "planId": "…", "status": "active", "title": "…", "subject": "reading", "classId": "…", "totalWeeks": 36, "createdAt": "…" } ] }
generate_challengeGenerate a challenge
challenges:write
async
POST /v1/agent/challenges

Create a quiz with generated exercises for a class and subject. Saved as a draft the teacher reviews in the dashboard unless publish is true (max 10 exercises).

Asynchronous: exercises are generated in the background; poll get_challenge.

InputTypeRequiredDescription
classIdstringyesClass
subjectenumyesmath | reading | grammar | clock | science | physics | history | computing
countinteger 1–10noExercises (default 5)
exerciseTypesstring[]noExercise types of the subject, e.g. fractions, word_problems
difficultystringnoeasy | medium | hard
unitIdstringnoCurriculum unit to target
topicstring ≤200noFree-text steer
publishbooleannoDefault false — drafts unless the teacher asks to publish

Returns

json
{ "challengeId": "…", "status": "generating", "title": "Fractions — quiz", "exerciseCount": 0, "preview": [],
  "publishOnReady": false, "dashboardUrl": "https://samiolearning.com/schools/dashboard/challenges?challenge=…", "provenance": "…" }
get_challengeGet one challenge
challenges:write
GET /v1/agent/challenges/:challengeId

Status and preview of a challenge created with generate_challenge: generating, draft, published or failed, with the generated questions once ready.

InputTypeRequiredDescription
challengeIdstringyeschallengeId from generate_challenge

Returns

json
{ "challengeId": "…", "status": "draft", "title": "Fractions — quiz", "subject": "math", "classId": "…", "exerciseCount": 5,
  "preview": [ { "type": "fractions", "question": "Which fraction is larger: 2/3 or 3/5?" }, … ],
  "dashboardUrl": "https://samiolearning.com/schools/dashboard/challenges?challenge=…" }
search_knowledge_factsSearch knowledge facts
knowledge:read
GET /v1/agent/knowledge/facts?subject&topic&language&limit

Samio's verified, sourced facts on a topic — the same facts that ground generated lessons and materials (max 20).

InputTypeRequiredDescription
subjectenumyesmath | reading | grammar | clock | science | physics | history | computing
topicstring 2–120yesTopic, e.g. photosynthesis
languagestringnoDefaults to the school's
limitinteger 1–20noDefault 10

Returns

json
{ "facts": [ { "factId": "…", "statement": "Photosynthesis converts light energy into chemical energy.", "subject": "science", "topic": "photosynthesis", "language": "en", "sources": [ { "title": "…", "url": "…" } ], "verified": true } ] }
get_class_curriculum_progressClass curriculum coverage
analytics:read
GET /v1/agent/classes/:classId/curriculum-progress?subject

Which official curriculum units a class has mastered, is working on or has not started, for one subject. A class rollup — never per-student rows.

InputTypeRequiredDescription
classIdstringyesClass
subjectenumyesmath | reading | grammar | clock | science | physics | history | computing

Returns

json
{ "classId": "…", "subject": "math", "standard": { "standardId": "…", "officialName": "…", "gradeName": "…" },
  "coverage": { "percent": 42, "unitsMastered": 5, "unitsInProgress": 3, "unitsPending": 4 },
  "units": [ { "unitId": "…", "name": "Fractions", "status": "in_progress", "percent": 61 } ] }

Discovery

http
# Authorization server (RFC 8414; the same document is also served OIDC-shaped for ChatGPT)
GET https://api.samiolearning.com/oauth/.well-known/oauth-authorization-server
GET https://api.samiolearning.com/.well-known/oauth-authorization-server/oauth
GET https://api.samiolearning.com/oauth/.well-known/openid-configuration
GET https://api.samiolearning.com/oauth/jwks.json

# Protected resource (RFC 9728) — what the 401 from /mcp points at
GET https://mcp.samiolearning.com/.well-known/oauth-protected-resource
→ { "resource": "https://mcp.samiolearning.com/mcp",
    "authorization_servers": ["https://api.samiolearning.com/oauth"],
    "scopes_supported": ["openid", "email", "classes:read", "materials:write", "plans:write", "challenges:write", "knowledge:read", "analytics:read"],
    "bearer_methods_supported": ["header"],
    "resource_documentation": "https://samiolearning.com/developers#mcp" }

Notes for developers building a client

  • Client registration: prefer a Client ID Metadata Document — your client_id is an https URL serving JSON with redirect_uris, client_name, client_uri, logo_uri (fetched with a 3 s timeout, cached one hour). Dynamic Client Registration (RFC 7591, POST /oauth/register) is also accepted. Redirect-URI hosts must be on the allow-list (claude.ai, chatgpt.com, chat.openai.com, platform.openai.com, localhost, 127.0.0.1); http://localhost and http://127.0.0.1 match port-agnostically (RFC 8252 §7.3). Both mechanisms produce public clients (token_endpoint_auth_method: "none").
  • PKCE S256 is mandatory; response_type=code only. Pass resource=https://mcp.samiolearning.com/mcp (RFC 8707) — it becomes the token's audience.
  • Tokens: POST /oauth/token accepts form-urlencoded and JSON; access tokens are RS256 JWTs valid one hour; refresh tokens live 30 days and rotate on every use — presenting an already-rotated token revokes the whole family. POST /oauth/revoke always answers 200.
  • No client_credentials grant: every connection is a teacher consenting on the screen above. Service-to-service access to the curriculum tools uses the app key below instead.
  • Same schemas in the browser: signed-in dashboard pages register the twelve teacher tools (all but get_my_account) through WebMCP with identical names and input schemas, executed with the teacher's session — see Agent tools (WebMCP).

Prefer plain REST? The agent gateway

Every tool is a thin wrapper over one endpoint of the Samio API’s agent gateway. Developers who would rather call HTTP than MCP can use the curriculum endpoints directly with an app key sent asX-Samio-Agent-Key(request one at info@samiolearning.com). The OpenAPI 3.1 description is public.

http
GET https://api.samiolearning.com/v1/agent/openapi.json                  # public, no key
GET https://api.samiolearning.com/v1/agent/curriculum/countries
GET https://api.samiolearning.com/v1/agent/curriculum/standards?country=NL&subject=math&age=7&query=optellen
GET https://api.samiolearning.com/v1/agent/curriculum/units/{unitId}?standardId={standardId}
GET https://api.samiolearning.com/v1/agent/pricing?country=MX

# errors are { "error": "...", "code": "..." }
# 400 INVALID_COUNTRY | INVALID_SUBJECT | INVALID_GRADE | INVALID_AGE | INVALID_LANGUAGE | INVALID_QUERY | INVALID_LIMIT
# 401 AGENT_KEY_INVALID · 403 AGENT_APP_DISABLED · 404 NO_CURRICULUM | UNIT_NOT_FOUND
# 429 AGENT_QUOTA_EXCEEDED (+ Retry-After) · 503 AGENT_ACCESS_DISABLED

# Teacher endpoints (Tier B) take BOTH the app key and the teacher's OAuth bearer:
GET  https://api.samiolearning.com/v1/agent/me
GET  https://api.samiolearning.com/v1/agent/classes
POST https://api.samiolearning.com/v1/agent/teaching-materials          # 202 { materialId, status: "generating" }
GET  https://api.samiolearning.com/v1/agent/teaching-materials/{materialId}
POST https://api.samiolearning.com/v1/agent/topic-plans                 # 202 { planId, status: "generating" }
GET  https://api.samiolearning.com/v1/agent/topic-plans/{planId}
GET  https://api.samiolearning.com/v1/agent/topic-plans/{planId}/weeks/{n}
POST https://api.samiolearning.com/v1/agent/challenges
GET  https://api.samiolearning.com/v1/agent/knowledge/facts?subject=&topic=
GET  https://api.samiolearning.com/v1/agent/classes/{classId}/curriculum-progress?subject=
# 401 AGENT_TOKEN_INVALID · 403 AGENT_SCOPE_MISSING | AGENT_GRANT_REVOKED · 402 PLAN_LIMIT_REACHED
# 404 CLASS_NOT_FOUND | PLAN_NOT_FOUND | MATERIAL_NOT_FOUND | WEEK_NOT_FOUND · 409 GENERATION_IN_PROGRESS
# 429 AGENT_SCHOOL_QUOTA_EXCEEDED (+ Retry-After)
  • Quotas: 600 calls per hour per app key and 120 per hour per client IP for developer apps; the MCP endpoint itself allows 120 requests per hour per IP. Curriculum responses carry Cache-Control: public, max-age=3600.
  • Audit: one row per call with the route template, status, duration, a hash of the inputs and a salted hash of the IP; no free text, no personal data, purged after 180 days.
  • The tool names and input schemas are identical on the MCP server and in the gateway’s OpenAPI file, so a client can switch between the two without remapping.

Problems, feature requests or a developer key: info@samiolearning.com. The gateway can be switched off centrally; when it is, every call answers 503 AGENT_ACCESS_DISABLED.

Samio Learning — Edu-V API v1.0.0