API
This is a list of the endpoints in the site. It includes both those that would
be adequately described as API endpoints, as well as internal endpoints that are
used for the UI. They are automatically created from the CLOS methods, hence the
format: it follow's Snooze's approach, and so Database content (entity records, claims, sources) is CC-BY-SA-4.0
; the ontology, SHACL shapes, and JSON-LD context are CC0-1.0
. The maker separately reserves the EU sui generis database right and TDM
rights under DSM Art. 4 for the database tier - see Licensing
for the full notice, including the research-use carve-out under DSM Art. 3.
Attribution (short form; see Licensing for
the standard and academic forms): Every response carries a &OPTIONAL
arguments are URI path components, and &KEY arguments are URL
query parameters
Licensing
Martialis (https://martial.is), CC BY-SA
4.0.
Link:
rel="license" header and a tdm-reservation
header; /.well-known/tdmrep.json states the reservation
machine-readably per rule, and /api/info restates it in the
API's own terms.
Infrastructure endpoints
Served by plain Hunchentoot dispatchers rather than Snooze resources, so they don't appear in the generated table below.
| Method | Path | Type | Description |
|---|---|---|---|
GET
| /data.ttl
| text/turtle
| Full RDF export of the database (dcat:Dataset with license/rights triples). |
GET
| /context.jsonld
| application/ld+json
| The JSON-LD @context every entity document references. |
GET
| /sitemap.xml
| application/xml
| Crawler sitemap, generated live from the database. |
GET
| /ontology[.ttl|/...]
| text/html or text/turtle
| Ontology/OWL documentation, content-negotiated. CC0-1.0, unreserved for TDM. |
GET
| /vocab[.ttl|/...]
| text/html or text/turtle
| SKOS controlled vocabularies, content-negotiated. CC0-1.0, unreserved for TDM. |
GET
| /llms.txt
| text/plain
| Orientation layer for AI agents, proxied from martialis-db. |
GET
| /robots.txt
| text/plain
| Crawler policy, including the Content-Signal TDM preference. |
GET
| /.well-known/tdmrep.json
| application/json
| Machine-readable TDM reservation (W3C TDMRep). |
GET
| /api/graph
| application/json
| SPARQL-backed graph slice: nodes/edges around a center entity. |
GET
| /api/info
| application/json
| Graph counts plus licence/rights/attribution metadata. |
GET
| /api/node
| application/json
| Outgoing/incoming triples for one node (?id=). |
GET
| /api/predicates
| application/json
| Every predicate in the graph, most-used first. |
GET
| /api/type-counts
| application/json
| Entity counts per rdf:type. |
GET
| /api/types
| application/json
| Every rdf:type present in the graph. |
Application routes
| Method | Path | Type | Args | Description |
|---|---|---|---|---|
get
| /about
| text/html
| ||
get
| /agent
| text/turtle
| (&optional slug) | |
get
| /agent
| application/json
| (&optional slug) | |
get
| /agent
| application/ld+json
| (&optional slug) | |
get
| /agent
| text/html
| (&optional slug) | A minimal page for SLUG: name, title and affiliation. |
get
| /api-doc
| text/html
| List every Snooze route (verb, path, content-type, args, docstring) in a web page. | |
get
| /auth-callback
| text/html
| (&key code) | Exchange the auth code for tokens, verify, set the session cookie. CODE and the error params are read off the request, not Snooze's &key arg. |
post
| /auth-delete-account
| application/x-www-form-urlencoded
| Permanently delete the current user's Supabase account and sign them out. Irreversible; the /settings UI gates this behind an in-page confirmation step before submitting. | |
get
| /auth-email
| text/html
| (&key sent) | SENT is read off the query string, not Snooze's &key arg. |
post
| /auth-email
| application/x-www-form-urlencoded
| (&key sent) | Request a magic-link sign-in/registration email. Register and sign-in are the same flow. SENT is unused here (POST never receives it) but CLOS requires every method's lambda list to be congruent. |
get
| /auth-login
| text/html
| (&key provider) | Begin the OAuth dance: stash a fresh PKCE verifier in a cookie and redirect to Supabase's /authorize endpoint. PROVIDER is read off the query string, not Snooze's &key arg. |
get
| /auth-logout
| text/html
| Clear the session cookie and redirect home. | |
get
| /bookmarks
| text/html
| ||
get
| /countries
| text/html
| (&optional code) | The country page for CODE, the list of every country otherwise. |
post
| /db-webhook
| application/json
| ||
post
| /db-webhook
| application/json
| ||
get
| /discussions
| text/html
| ||
get
| /entity
| text/turtle
| (&optional id) | |
get
| /entity
| application/json
| (&optional id) | |
get
| /entity
| application/ld+json
| (&optional id) | |
get
| /entity
| text/html
| (&optional id) | Redirect to ID's real page with a 303 (correct Linked Data dereferencing). A claim goes to its record's page, anchored at the claim. |
get
| /events
| text/turtle
| (&optional id) | |
get
| /events
| application/json
| (&optional id) | |
get
| /events
| application/ld+json
| (&optional id) | |
get
| /events
| text/html
| (&optional id) | Event page for ID, the list of every event otherwise. |
get
| /graph
| text/html
| (&optional entity &key generations all contextual) | Render the graph page. See file header for URL semantics. |
get
| /home
| text/html
| ||
get
| /lang
| text/html
| (&key code) | Set the UI language cookie to CODE and redirect back. |
get
| /licensing
| application/ld+json
| ||
get
| /licensing
| application/json
| ||
get
| /licensing
| text/html
| ||
get
| /mapping
| text/html
| (&optional id) | |
get
| /model
| text/html
| ||
get
| /og
| image/svg+xml
| (&optional kind id) | The unrasterized SVG, regenerated on every request so template edits show up on reload. |
get
| /og
| image/png
| (&optional kind id) | The rasterized card - see SERVE-OG-CARD-FILE for the shared headers. |
get
| /og-p
| image/svg+xml
| (&optional public-id) | The unrasterized SVG: the design/debugging entry point, never cached. |
get
| /og-p
| image/png
| (&optional public-id) | The rasterized profile card (PROFILE-SOCIAL-CARD's og:image). Uses the shared cache/lock/semaphore machinery (ENSURE-OG-CARD-FOR). |
get
| /og-path
| image/svg+xml
| (&optional from to) | The unrasterized SVG, regenerated on every request. |
get
| /og-path
| image/png
| (&optional from to) | The rasterized card - see SERVE-OG-CARD-FILE for the shared headers. |
get
| /og-site
| image/svg+xml
| (&optional name) | The unrasterized SVG, regenerated on every request. |
get
| /og-site
| image/png
| (&optional name) | The rasterized site card - see SERVE-OG-CARD-FILE for the shared headers. |
get
| /ontology
| text/turtle
| (&optional section subsection) | The ontology, SHACL and alignment Turtle documents. Snooze strips a .ttl suffix and matches this route (db/rdf.lisp registers the extension), so /ontology.ttl, /ontology/shapes/quality.ttl and the alignment import all resolve here. |
get
| /ontology
| text/html
| (&optional section subsection) | The /ontology, /ontology/shapes and /ontology/shapes/<role> documentation pages. The shapes graphs have no page of their own: each 302s to its anchored card on /model. |
get
| /orgs
| text/turtle
| (&optional id) | |
get
| /orgs
| application/json
| (&optional id) | |
get
| /orgs
| application/ld+json
| (&optional id) | |
get
| /orgs
| text/html
| (&optional id) | Organization page for ID, the list of every organization otherwise. |
get
| /p
| text/html
| (&optional public-id) | |
get
| /path
| text/html
| (&optional from to &key all) | |
get
| /persons
| text/turtle
| (&optional id) | |
get
| /persons
| application/json
| (&optional id) | |
get
| /persons
| application/ld+json
| (&optional id) | |
get
| /persons
| text/html
| (&optional id) | Person page for ID, the list of every person otherwise. |
get
| /places
| text/turtle
| (&optional id) | |
get
| /places
| application/json
| (&optional id) | |
get
| /places
| application/ld+json
| (&optional id) | |
get
| /places
| text/html
| (&optional id) | Place page for ID, the list of every place otherwise. |
get
| /privacy
| text/html
| ||
get
| /profile
| text/html
| ||
get
| /ranking-methodology
| text/html
| ||
get
| /rankings
| text/html
| ||
get
| /reload
| text/html
| Trigger a manual reload. Off unless MARTIALIS_ENABLE_RELOAD is set (a restart applies a new database), and then it needs a login. | |
get
| /settings
| text/html
| ||
get
| /sources
| text/turtle
| (&optional id) | |
get
| /sources
| application/json
| (&optional id) | |
get
| /sources
| application/ld+json
| (&optional id) | |
get
| /sources
| text/html
| (&optional id) | Source page for ID, the list of every source otherwise. |
get
| /sparql
| application/sparql-results+json
| (&key query &allow-other-keys) | The endpoint *SPARQL-QUERY-ENDPOINT* points the explorer at. Gated as the page route; a 404 (not a redirect) when not visible, since this is a data API. &ALLOW-OTHER-KEYS keeps the lambda list congruent with the resource's. |
get
| /sparql
| text/html
| (&key query &allow-other-keys) | QUERY is declared only so Snooze accepts ?query=...; it is read client-side, never server-side. &ALLOW-OTHER-KEYS lets ?center= through. |
post
| /sparql
| application/sparql-results+json
| (&key query &allow-other-keys) | Same as the GET route; POST allows queries too long for a URL query string. &ALLOW-OTHER-KEYS for the same lambda-list-congruence reason. |
get
| /style-graph
| text/html
| (&optional entity &key generations) | |
get
| /styles
| text/turtle
| (&optional id) | |
get
| /styles
| application/json
| (&optional id) | |
get
| /styles
| application/ld+json
| (&optional id) | |
get
| /styles
| text/html
| (&optional id) | Style page for ID, the list of every style otherwise. |
get
| /stylesheet
| text/css
| (&optional id) | |
get
| /support
| text/html
| ||
get
| /timeline
| text/html
| (&optional focus) | |
post
| /ui-bookmark-toggle
| application/json
| (&key datastar id list) | Flip bookmark ID for the signed-in user and patch the button into its new state. Adding is checked before the RPC - ID must name a database record and the cap must not be reached - though ADD_BOOKMARK (sql/migrations/0020_bookmarks.sql) re-checks its own looser ceiling. Removing needs no such check: it is scoped to the caller's own rows by RLS, and a row whose entity has left the database must stay removable. |
get
| /ui-graph-contextual
| text/html
| (&key datastar) | |
get
| /ui-graph-expand
| application/json
| (s &key contextual) | |
get
| /ui-graph-expand
| application/json
| (p &key contextual) | |
get
| /ui-graph-focus
| text/html
| (s &key datastar (graph-kind graph)) | |
get
| /ui-graph-focus
| text/html
| (p &key datastar graph-kind) | |
get
| /ui-graph-help
| text/html
| (&key datastar) | |
get
| /ui-graph-reset
| text/html
| (&key datastar) | |
get
| /ui-listing
| text/html
| (&key datastar (kind persons)) | Re-render the filtered/sorted listing fragment for KIND. Validates KIND before opening the SSE stream, since an error raised inside WITH-SSE can no longer become a clean HTTP status. |
get
| /ui-live
| text/html
| (&key datastar topics) | |
get
| /ui-path
| text/html
| (&key datastar swap) | |
post
| /ui-path
| application/json
| (&key datastar swap) | |
post
| /ui-profile-claim
| application/json
| (&key datastar) | Validate the claim request, then hand it to the mail worker. Every check is server-side: the button's disabled attribute is a courtesy. The person must resolve in the local corpus (a claim about an id that does not exist is never useful), the evidence must say something, the email must be usable, and the account must not have asked a moment ago. |
post
| /ui-profile-claim-release
| application/json
| (&key datastar) | Clear the caller's own confirmation (RELEASE-OWN-IDENTITY-CLAIM), then reload so the section shows the request form again. The checkbox is checked here too: the button's disabled attribute is a courtesy. |
post
| /ui-profile-handle
| application/json
| (&key datastar) | Claim the caller's permanent /@handle, exactly once. Set-once, never-reuse, and the reserved list are enforced in Postgres - by CLAIM-USER-SLUG's RPC plus a guard trigger on profiles.slug and profiles.public_id (sql/migrations/0006_profile_handles.sql) - not here, so they hold even against a direct PATCH or RPC call that bypasses this route. |
post
| /ui-profile-link
| application/json
| (&key datastar) | Add the picked person as a new lineage claim, then patch the whole claims block with the fresh list. Two checks before the RPC, both of which the UI already implies but neither of which it can be trusted to enforce: the target must resolve to a real database person (GET-PERSON-BY-ID is a local lookup - the picker only ever offers these, but a direct POST can name anything), and the caller's own cap must not already be reached. ADD-PROFILE-LINK (sql/migrations/0007_profile_links_limit.sql) re-checks its own looser abuse ceiling underneath; this is the user-facing 5. |
post
| /ui-profile-publish
| application/json
| (&key datastar) | Publish or unpublish. A Datastar boolean signal is T when checked and :FALSE (not NIL) when unchecked, so normalise before saving. |
post
| /ui-profile-save
| application/json
| (&key datastar) | Display name and bio only. PHOTO-URL is never accepted: the photo always follows the OAuth avatar. Length is checked here, before the write, so an over-long value gets a sentence naming the limit instead of the DB constraint error (which UPDATE-USER-PROFILE would collapse into the generic 'Couldn't save'). The CHECK constraints are the real backstop. |
post
| /ui-profile-set-style
| application/json
| (&key datastar) | Set STYLE-ID on the claim named by PROFILE.STYLETARGETID - set by that card's own "Add/Change style" button before the (page-level, shared) style picker's commit - then patch the whole claims block and close the picker. |
post
| /ui-profile-unlink
| application/json
| (&key datastar) | Remove one claim - PROFILE.ACTIONTARGET, set by that card's own button just before this POST (RENDER-PROFILE-LINK-CARD) - then patch the whole claims block with the fresh list. |
post
| /ui-profile-unset-style
| application/json
| (&key datastar) | Clear the style on the claim named by PROFILE.ACTIONTARGET, then patch the whole claims block. |
get
| /ui-search
| text/html
| (&key datastar (mode navigate)) | Search every kind in +SEARCH-KINDS+ by name, or run a registered picker (see REGISTER-PICKER) when MODE names one. |
post
| /ui-settings-focus
| application/json
| (&key datastar) | |
post
| /ui-settings-locale
| application/json
| (&key datastar) | |
post
| /ui-settings-marketing
| application/json
| (&key datastar) | Save or withdraw the newsletter opt-in (GDPR Art. 7(3): withdrawing must be as easy as giving consent). A Datastar boolean is T when checked and :FALSE (not NIL) when unchecked, so normalise before saving. Report success only when UPSERT-USER-SETTING actually succeeds. |
get
| /ui-show-all
| text/html
| (&key datastar) | |
get
| /ui-style-graph-help
| text/html
| (&key datastar) | |
get
| /ui-style-graph-reset
| text/html
| (&key datastar) | |
post
| /ui-suggestion-save
| application/json
| (&key datastar) | |
get
| /ui-timeline
| text/html
| (&key datastar) | Re-lay out #timeline-track for the zoom, lanes and kind signals, update the status, then scroll back to the axis position the view was centred on (tl.x). The selected entry is pinned, so it survives every zoom. |
get
| /vocab
| text/turtle
| (&optional scheme concept) | The vocabularies file, or one scheme's slice. A concept or collection IRI resolves to the scheme document containing it. |
get
| /vocab
| text/html
| (&optional scheme concept) | The /vocab index, a /vocab/<scheme> page, or the scheme page a /vocab/<scheme>/<concept> IRI names (302 to the concept's anchor). |