<https://www.w3.org/TR/sparql11-http-rdf-update/>
        <http://purl.org/dc/terms/title>
                "SPARQL 1.1 Graph Store HTTP Protocol" .

<https://docs.linkeddatahub.com/reference/http-api/#content>
        a       <https://w3id.org/atomgraph/linkeddatahub#XHTML>;
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#value>
                "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n    <p class=\"ldh-body-lg\">Read and write RDF data from and to LinkedDataHub dataspaces over HTTP</p>\n    <p>LinkedDataHub implements a uniform, generic RESTful Linked Data API as defined by the\n        <a href=\"https://www.w3.org/TR/sparql11-http-rdf-update/\" target=\"_blank\">SPARQL 1.1 Graph Store HTTP Protocol</a>. It adds a few conventions of its own, however — such as <a href=\"#document-metadata\">automatic document metadata</a> — as well as some <a href=\"#constraints\">constraints</a>.</p>\n    <div>\n        <h2 id=\"auth\">Authentication</h2>\n        <p>The LinkedDataHub UI supports two authentication methods:</p>\n        <ul>\n            <li><a href=\"https://dvcs.w3.org/hg/WebID/raw-file/tip/spec/tls-respec.html\" target=\"_blank\">WebID-TLS</a> using TLS client certificates</li>\n            <li>OpenID Connect using <a href=\"https://developers.google.com/identity/protocols/oauth2/openid-connect\" target=\"_blank\">Google</a> or <a href=\"https://info.orcid.org/documentation/integration-guide/\" target=\"_blank\">ORCID</a></li>\n        </ul>\n        <p>See how those authentication methods can be <a href=\"../configuration/\">configured</a> or how to <a href=\"../../get-started/get-an-account/\">get an account</a> on LinkedDataHub.</p>\n        <div class=\"ac-alert va-informative\" role=\"status\">\n            <span class=\"ac-alert-ic\"><span aria-hidden=\"true\" class=\"msi outline\">info</span></span>\n            <div class=\"ac-alert-body\">\n                <p class=\"ac-alert-text\">HTTP API access using the <a href=\"../command-line-interface/\">CLI</a> or curl currently does not support the OIDC method.</p>\n            </div>\n        </div>\n    </div>\n    <div>\n        <h2 id=\"acl\">Access control</h2>\n        <p>All HTTP access to <a href=\"#documents\">documents</a> is subject to <a href=\"../administration/acl/\">access\n            control</a>. Requesting a document with insufficient access rights will result in a <code>403 Forbidden</code> response. That means either:</p>\n        <ul>\n            <li>the user is not authenticated and public access to the document is not allowed</li>\n            <li>the user is authenticated but the associated agent does not have an authorization to <a href=\"../data-model/documents/#management\">perform the action</a> on the\n                requested document</li>\n        </ul>\n    </div>\n    <div>\n        <h2 id=\"con-neg\">Content negotiation</h2>\n        <p>LinkedDataHub implements <a href=\"https://tools.ietf.org/html/rfc7231#section-3.4.1\" target=\"_blank\">proactive content negotiation</a> based on the request <code>Accept</code>\n            header value. The following RDF media types are supported:</p>\n        <table>\n            <caption class=\"ac-vh\">Supported formats and their media types</caption>\n            <thead>\n                <tr>\n                    <th scope=\"col\">Format</th>\n                    <th scope=\"col\">Media type</th>\n                    <th scope=\"col\">Direction</th>\n                </tr>\n            </thead>\n            <tbody>\n                <tr>\n                    <th scope=\"row\"><a href=\"https://www.w3.org/TR/turtle/\" target=\"_blank\">Turtle</a></th>\n                    <td><code>text/turtle</code></td>\n                    <td>Request, response</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><a href=\"https://www.w3.org/TR/n-triples/\" target=\"_blank\">N-Triples</a></th>\n                    <td><code>application/n-triples</code></td>\n                    <td>Request, response</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><a href=\"https://www.w3.org/TR/rdf-syntax-grammar/\" target=\"_blank\">RDF/XML</a></th>\n                    <td><code>application/rdf+xml</code></td>\n                    <td>Request, response</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><a href=\"https://www.w3.org/TR/json-ld/\" target=\"_blank\">JSON-LD</a></th>\n                    <td><code>application/ld+json</code></td>\n                    <td>Request, response</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><a href=\"https://atomgraph.github.io/RDF-POST/\" target=\"_blank\">RDF/POST</a></th>\n                    <td><code>application/x-www-form-urlencoded</code></td>\n                    <td>Request only</td>\n                </tr>\n            </tbody>\n        </table>\n        <p>The same document, negotiated as N-Triples:</p>\n        <pre>GET /products/1/ HTTP/1.1\nHost: localhost:4443\nAccept: application/n-triples\n\nHTTP/1.1 200 OK\nContent-Type: application/n-triples\nETag: \"1e635b4-ntriples\"\n\n&lt;https://localhost:4443/products/1/#this&gt; &lt;https://schema.org/name&gt; \"Chai\" .\n…</pre>\n    </div>\n    <div>\n        <h2 id=\"errors\">Error responses</h2>\n        <p>LinkedDataHub provides machine-readable error responses in the requested RDF format. An example of <code>403 Forbidden</code>:</p>\n        <pre>@prefix xsd:  &lt;http://www.w3.org/2001/XMLSchema#&gt; .\n@prefix http: &lt;http://www.w3.org/2011/http#&gt; .\n@prefix sc:   &lt;http://www.w3.org/2011/http-statusCodes#&gt; .\n@prefix dct:  &lt;http://purl.org/dc/terms/&gt; .\n\n[ a http:Response ;\n    dct:title \"Access not authorized\" ;\n    http:reasonPhrase \"Forbidden\" ;\n    http:sc sc:Forbidden ;\n    http:statusCodeValue \"403\"^^xsd:long\n] .</pre>\n    </div>\n    <div>\n        <h2 id=\"documents\">Managing documents</h2>\n        <p>Every document is also a <a href=\"../dataset/#structure\">named graph</a> in the dataspace's RDF dataset. LinkedDataHub supports the SPARQL Graph Store Protocol's <a href=\"https://www.w3.org/TR/sparql11-http-rdf-update/#direct-graph-identification\" target=\"_blank\">direct graph identification</a> as the HTTP CRUD protocol for managing document data.</p>\n        <div class=\"ac-alert va-informative\" role=\"status\">\n            <span class=\"ac-alert-ic\"><span aria-hidden=\"true\" class=\"msi outline\">info</span></span>\n            <div class=\"ac-alert-body\">\n                <p class=\"ac-alert-text\">GSP <a href=\"https://www.w3.org/TR/sparql11-http-rdf-update/#indirect-graph-identification\" target=\"_blank\">indirect graph identification</a> is not supported starting with LinkedDataHub version 5.x.</p>\n            </div>\n        </div>\n        <p>The API also supports the <code>PATCH</code> HTTP method which is <a href=\"https://www.w3.org/TR/sparql11-http-rdf-update/#http-patch\">optional in GSP</a>. It accepts graph-scoped SPARQL updates that will modify the requested document. Only the <code>INSERT/WHERE</code> and <code>DELETE WHERE</code> forms are supported; <code>GRAPH</code> patterns are not allowed.</p>\n        <p>Trailing slashes in document URIs are enforced using <code>308 Permanent Redirect</code> responses.</p>\n        <table>\n            <caption class=\"ac-vh\">HTTP methods and the responses they return</caption>\n            <thead>\n                <tr>\n                    <th scope=\"col\">Method</th>\n                    <th scope=\"col\">Description</th>\n                    <th scope=\"col\">Success</th>\n                    <th scope=\"col\">Failure</th>\n                    <th scope=\"col\">Reason</th>\n                </tr>\n            </thead>\n            <tbody>\n                <tr>\n                    <th rowspan=\"2\" scope=\"row\"><code id=\"ld-get\">GET</code></th>\n                    <td rowspan=\"2\">Returns the data of a document</td>\n                    <td rowspan=\"2\"><code>200 OK</code></td>\n                    <td><code>404 Not Found</code></td>\n                    <td>Document with request URI not found</td>\n                </tr>\n                <tr>\n                    <td><code>406 Not Acceptable</code></td>\n                    <td><a href=\"#con-neg\">Media type</a> not supported</td>\n                </tr>\n                <tr>\n                    <th rowspan=\"5\" scope=\"row\"><code id=\"ld-post\">POST</code></th>\n                    <td rowspan=\"5\">Appends data to a document</td>\n                    <td rowspan=\"5\"><code>204 No Content</code></td>\n                    <td><code>400 Bad Request</code></td>\n                    <td>RDF syntax error</td>\n                </tr>\n                <tr>\n                    <td><code>404 Not Found</code></td>\n                    <td>Document with request URI not found</td>\n                </tr>\n                <tr>\n                    <td><code>413 Payload Too Large</code></td>\n                    <td>Request body too large</td>\n                </tr>\n                <tr>\n                    <td><code>415 Unsupported Media Type</code></td>\n                    <td><a href=\"#con-neg\">Media type</a> not supported</td>\n                </tr>\n                <tr>\n                    <td><code>422 Unprocessable Entity</code></td>\n                    <td><a href=\"../administration/ontologies/#constraints\">Constraint</a> violation</td>\n                </tr>\n                <tr>\n                    <th rowspan=\"5\" scope=\"row\"><code id=\"ld-put\">PUT</code></th>\n                    <td rowspan=\"5\">Upserts a document</td>\n                    <td rowspan=\"5\"><code>200 OK</code><br></br><code>201 Created</code><br></br><code>308 Permanent Redirect</code></td>\n                    <td rowspan=\"2\"><code>400 Bad Request</code></td>\n                    <td>RDF syntax error</td>\n                </tr>\n                <tr>\n                    <td>Malformed document URI</td>\n                </tr>\n                <tr>\n                    <td><code>413 Payload Too Large</code></td>\n                    <td>Request body too large</td>\n                </tr>\n                <tr>\n                    <td><code>415 Unsupported Media Type</code></td>\n                    <td><a href=\"#con-neg\">Media type</a> not supported</td>\n                </tr>\n                <tr>\n                    <td><code>422 Unprocessable Entity</code></td>\n                    <td><a href=\"../administration/ontologies/#constraints\">Constraint</a> violation</td>\n                </tr>\n                <tr>\n                    <th rowspan=\"2\" scope=\"row\"><code id=\"ld-delete\">DELETE</code></th>\n                    <td rowspan=\"2\">Removes the requested document</td>\n                    <td rowspan=\"2\"><code>204 No Content</code></td>\n                    <td><code>404 Not Found</code></td>\n                    <td>Document with request URI not found</td>\n                </tr>\n                <tr>\n                    <td><code>405 Method Not Allowed</code></td>\n                    <td>Deleting root, owner, or secretary documents is not allowed</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><code id=\"ld-patch\">PATCH</code></th>\n                    <td>Modifies a document using SPARQL Update</td>\n                    <td><code>204 No Content</code></td>\n                    <td><code>422 Unprocessable Entity</code></td>\n                    <td>SPARQL update string violates syntax constraints</td>\n                </tr>\n            </tbody>\n        </table>\n        <p>Any method may additionally answer <code>403 Forbidden</code> — see <a href=\"#acl\">Access control</a>. Any method that writes may answer <code>428 Precondition Required</code> when the request carries no precondition, or <code>412 Precondition Failed</code> when the one it carries is out of date — see <a href=\"#preconditions\">Conditional writes</a>.</p>\n        <div>\n            <h3 id=\"document-metadata\">Document metadata</h3>\n            <p>Since LinkedDataHub 5, the <a href=\"../data-model/documents/#hierarchy\">document hierarchy</a> is managed automatically.</p>\n            <p>By default, LinkedDataHub treats an RDF document as an item by giving it the <code>dh:Item</code> type and attaching it to the parent container using <code>sioc:has_container</code>. If the client wants to create a container instead, it has to explicitly add the <code>dh:Container</code> type on the document resource; the new container will be attached to its parent using <code>sioc:has_parent</code>. In either case, the URI of the new document will be relative to its parent's.</p>\n            <p>LinkedDataHub will also manage additional document metadata, such as its owner and creation/modification timestamps.</p>\n            <p>For example, this HTTP request creating the Northwind regions container (Turtle syntax):</p>\n            <pre>PUT /regions/ HTTP/1.1\nHost: localhost:4443\nContent-Type: text/turtle\n\n@prefix dh:     &lt;https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#&gt; .\n@prefix dct:    &lt;http://purl.org/dc/terms/&gt; .\n\n&lt;&gt; a dh:Container ;\n    dct:title \"Regions\" .</pre>\n            <p>will produce the following document triples:</p>\n            <pre>@prefix dh:     &lt;https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#&gt; .\n@prefix dct:    &lt;http://purl.org/dc/terms/&gt; .\n@prefix xsd:    &lt;http://www.w3.org/2001/XMLSchema#&gt; .\n@prefix sioc:   &lt;http://rdfs.org/sioc/ns#&gt; .\n@prefix acl:    &lt;http://www.w3.org/ns/auth/acl#&gt; .\n\n&lt;https://localhost:4443/regions/&gt;\n    a dh:Container ;\n    dct:created \"2025-03-31T21:46:21.984Z\"^^xsd:dateTime ;\n    dct:creator &lt;https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this&gt; ;\n    dct:title \"Regions\" ;\n    sioc:has_parent &lt;https://localhost:4443/&gt; ;\n    acl:owner &lt;https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this&gt; .</pre>\n            <p>The HTTP request to produce a new item can be empty:</p>\n            <pre>PUT /regions/1/ HTTP/1.1\nHost: localhost:4443\nContent-Type: text/turtle</pre>\n            <p>It will create an item document with the following triples:</p>\n            <pre>@prefix dh:     &lt;https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#&gt; .\n@prefix dct:    &lt;http://purl.org/dc/terms/&gt; .\n@prefix xsd:    &lt;http://www.w3.org/2001/XMLSchema#&gt; .\n@prefix sioc:   &lt;http://rdfs.org/sioc/ns#&gt; .\n@prefix acl:    &lt;http://www.w3.org/ns/auth/acl#&gt; .\n\n&lt;https://localhost:4443/regions/1/&gt;\n    a dh:Item ;\n    dct:created \"2025-03-31T20:45:42.802Z\"^^xsd:dateTime ;\n    dct:creator &lt;https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this&gt; ;\n    sioc:has_container &lt;https://localhost:4443/regions/&gt; ;\n    acl:owner &lt;https://admin.localhost:4443/acl/agents/865c2431-8436-4ae8-b300-2a531a013cd0/#this&gt; .</pre>\n        </div>\n        <div>\n            <h3 id=\"patch-example\">Graph-scoped updates</h3>\n            <p>A <code>PATCH</code> applies a SPARQL update scoped to the requested document's graph. The request body must contain a single update operation, in one of two forms: <code>DELETE</code>/<code>INSERT</code> with a <code>WHERE</code> clause (either template can be omitted, giving plain <code>INSERT { } WHERE { }</code> or <code>DELETE { } WHERE { }</code>), or the <code>DELETE WHERE</code> shorthand. Every other form is rejected with <samp>422 Unprocessable Entity</samp>, as is a body with more than one operation. Appending a description to the Chai product:</p>\n            <pre>PATCH /products/1/ HTTP/1.1\nHost: localhost:4443\nContent-Type: application/sparql-update\n\nPREFIX schema: &lt;https://schema.org/&gt;\n\nINSERT\n{\n    &lt;https://localhost:4443/products/1/#this&gt; schema:description \"A delicate black tea blend\" .\n}\nWHERE {}</pre>\n            <p>The update executes against that one graph, so <code>GRAPH</code> patterns are not allowed — this request is rejected with\n                <samp>422 Unprocessable Entity</samp>:</p>\n            <pre>PATCH /products/1/ HTTP/1.1\nHost: localhost:4443\nContent-Type: application/sparql-update\n\nPREFIX schema: &lt;https://schema.org/&gt;\n\nINSERT\n{\n    GRAPH &lt;https://localhost:4443/products/1/&gt;    # GRAPH is implied by the request URI — not allowed here\n    {\n        &lt;https://localhost:4443/products/1/#this&gt; schema:description \"A delicate black tea blend\" .\n    }\n}\nWHERE {}</pre>\n        </div>\n        <div>\n            <h3 id=\"constraints\">Built-in constraints</h3>\n            <p>LinkedDataHub has a few built-in constraints that are not found in the standard Graph Store Protocol:</p>\n            <ul>\n                <li>It is not possible to delete the root document (returns <code>405 Method Not Allowed</code>)</li>\n                <li>It is not possible to modify or delete the documents of the owner agent and the secretary agent (returns <code>405 Method Not Allowed</code>)</li>\n                <li>A document can only be created with a URL relative to an existing container (i.e. resolving <samp>..</samp> against the new document's URL must identify an existing container)</li>\n            </ul>\n            <p>The built-in constraints are similar to, but separate from the <a href=\"../administration/ontologies/#constraints\">ontology constraints</a>.</p>\n        </div>\n    </div>\n    <div>\n        <h2 id=\"preconditions\">Conditional writes</h2>\n        <p>A write to a document that already exists must say which state it was written against. Every write reads the document's graph, changes it in memory and writes the whole graph back, so two writers that name no precondition overwrite each other with nothing to show that anything was lost.</p>\n        <p>Such a write is answered <code>428 Precondition Required</code>. To make it conditional, send either:</p>\n        <ul>\n            <li><code>If-Match</code> with the document's current <code>ETag</code>, to modify what you read</li>\n            <li><code>If-None-Match: *</code>, to create a document only if it does not exist yet</li>\n        </ul>\n        <p>Creating a document needs no precondition — there is no prior state to have been written against — so a <code>PUT</code> to a URL that does not exist is accepted as it always was.</p>\n        <p>If the document changed since you read it, the write is refused <code>412 Precondition Failed</code>, and that response carries the document's current <code>ETag</code> so you can re-read, reapply your change and retry without an extra request. <code>If-None-Match: *</code> against a document that already exists is likewise refused <code>412</code>, which is how a client can create-or-append in two steps.</p>\n        <div class=\"ac-alert va-informative\" role=\"status\">\n            <span class=\"ac-alert-ic\"><span aria-hidden=\"true\" class=\"msi outline\">info</span></span>\n            <div class=\"ac-alert-body\">\n                <p class=\"ac-alert-text\">An <code>ETag</code> identifies a <em>negotiated representation</em>, not the graph alone: the same document answers a different tag as RDF/XML than as Turtle. Read the validator with the same <code>Accept</code> the write will send, or the write is refused <code>412</code>.</p>\n            </div>\n        </div>\n        <pre>HEAD /my/document/ HTTP/1.1\nAccept: application/n-triples\n\nHTTP/1.1 200 OK\nETag: \"f731c06f5ac4fec6490dff1399bd5440\"\n\nPATCH /my/document/ HTTP/1.1\nAccept: application/n-triples\nContent-Type: application/sparql-update\nIf-Match: \"f731c06f5ac4fec6490dff1399bd5440\"\n\nHTTP/1.1 204 No Content</pre>\n        <p><code>HEAD</code> is answered for any access mode the agent holds, not <code>acl:Read</code> alone, so an agent granted <code>acl:Write</code> or <code>acl:Append</code> can read the validator its writes have to quote without being able to read the document. <code>GET</code> still requires <code>acl:Read</code>.</p>\n        <p>The <a href=\"../command-line-interface/\">command line interface</a> does this for you: every <samp>ldh</samp> command that writes reads the document's validator first and sends it.</p>\n    </div>\n    <div>\n        <h2 id=\"versioned-documents\">Versioned documents</h2>\n        <p>In dataspaces with <a href=\"../versioning/\">versioning</a> enabled, document URLs accept additional query parameters that expose the version\n            history through the standard <a href=\"https://datatracker.ietf.org/doc/html/rfc7089\" target=\"_blank\">Memento (RFC 7089)</a> protocol:</p>\n        <dl>\n            <dt><code>?version=&lt;commit-sha&gt;</code></dt>\n            <dd>A historical version of the document, served with a <code>Memento-Datetime</code> header and an immutable <code>Cache-Control</code>. Snapshots are read-only: write methods answer <code>405 Method Not Allowed</code></dd>\n            <dt><code>?timemap</code></dt>\n            <dd>The document's version history — a TimeMap described with PROV-O in RDF formats, or in <code>application/link-format</code> as RFC 7089 requires</dd>\n            <dt><code>?timegate</code></dt>\n            <dd>Datetime negotiation: a request with an <code>Accept-Datetime</code> header answers <code>302 Found</code> with the closest version in <code>Location</code></dd>\n        </dl>\n        <p>See the <a href=\"../versioning/\">versioning reference</a> for details.</p>\n    </div>\n    <div>\n        <h2 id=\"sparql\">Executing SPARQL</h2>\n        <p>Every LinkedDataHub dataspace provides a SPARQL endpoint on <code>sparql</code> path (relative to the dataspace's base URI). It supports the\n            <a href=\"https://www.w3.org/TR/sparql11-protocol/\" target=\"_blank\">SPARQL 1.1 Protocol</a> and serves as a proxy for the backend endpoint of the\n            dataspace.</p>\n        <p>The protocol's dataset parameters can be used to scope a query to a single document's graph: passing <code>default-graph-uri=&lt;document-uri&gt;</code>\n            makes that document's named graph the query's default graph. The dataset specified this way overrides any <code>FROM</code>/<code>FROM NAMED</code>\n            clauses in the query, and <code>GRAPH</code> patterns match nothing since no named graphs are part of the dataset. This is the read-side counterpart\n            of the graph-scoped <code>PATCH</code> method. Reading the Chai product's name out of its document alone:</p>\n        <pre>curl -k -G \"https://localhost:4443/sparql\" \\\n  -H \"Accept: application/sparql-results+json\" \\\n  --data-urlencode 'query=PREFIX schema: &lt;https://schema.org/&gt; SELECT ?name WHERE { ?product a schema:Product ; schema:name ?name }' \\\n  --data-urlencode 'default-graph-uri=https://localhost:4443/products/1/'</pre>\n    </div>\n    <div>\n        <h2 id=\"ld-proxy\">Linked Data proxy</h2>\n        <p>LinkedDataHub works as a <dfn>Linked Data proxy</dfn> (from the end-user perspective, as a <dfn>Linked Data browser</dfn>) when a URL is provided using the <code>uri</code> query parameter.\n            All HTTP methods are supported.</p>\n        <p>If the URL dereferences successfully as RDF, LinkedDataHub forwards its response body (re-serializing it to enable content negotiation).\n            During a write request, the request body is forwarded to the provided URL.</p>\n        <p>If the URL returns an HTML document, LinkedDataHub extracts every embedded <a href=\"https://json-ld.org/\" target=\"_blank\">JSON-LD</a> script\n            (<code>&lt;script type=\"application/ld+json\"&gt;</code>) and parses it as RDF using JSON-LD 1.1. Pages annotated with <a href=\"https://schema.org/\" target=\"_blank\">schema.org</a> markup\n            can therefore be browsed as Linked Data. The schema.org JSON-LD context is bundled with LinkedDataHub and served locally, so no external network request is made to resolve it. A supplier's homepage carrying this markup:</p>\n        <pre>&lt;script type=\"application/ld+json\"&gt;\n{\n    \"@context\": \"https://schema.org/\",\n    \"@type\": \"Corporation\",\n    \"@id\": \"#this\",\n    \"legalName\": \"Exotic Liquids\",\n    \"telephone\": \"(171) 555-2222\"\n}\n&lt;/script&gt;</pre>\n        <p>browses as these triples:</p>\n        <pre>&lt;https://supplier.example/#this&gt; a schema:Corporation ;\n    schema:legalName \"Exotic Liquids\" ;\n    schema:telephone \"(171) 555-2222\" .</pre>\n        <p>The proxy only accepts external (non-relative to the current dataspace's base URI) URLs; local URLs have to be dereferenced directly.</p>\n        <p>The proxy forwards the origin's <code>ETag</code> and <code>Last-Modified</code> validators and passes conditional request headers\n            (<code>If-Match</code>, <code>If-None-Match</code>, <code>If-Modified-Since</code>, <code>If-Unmodified-Since</code>) through. Preconditioned\n            writes against proxied documents are therefore evaluated at the origin. Error statuses from the origin reach the client unchanged.</p>\n    </div>\n    <div>\n        <h2 id=\"federation\">Federation</h2>\n        <p>The Linked Data proxy makes dataspaces interoperable across origins: one dataspace's client can browse, query, and write to another\n            origin's dataspace, whether on the same LinkedDataHub instance or a different one.</p>\n        <p>Browsing a UNESCO Thesaurus concept from the Northwind dataspace, for example, the proxy forwards the remote dataspace's hypermedia along\n            with the RDF:</p>\n        <pre>GET /?uri=https%3A%2F%2Funesco-thesaurus.demo.linkeddatahub.com%2Fconcepts%2Fconcept3683%2F HTTP/1.1\nHost: northwind-traders.demo.linkeddatahub.com\nAccept: application/rdf+xml\n\nHTTP/1.1 200 OK\nContent-Type: application/rdf+xml\nLink: &lt;https://unesco-thesaurus.demo.linkeddatahub.com/sparql&gt;; rel=\"http://www.w3.org/ns/sparql-service-description#endpoint\"</pre>\n        <ul>\n            <li>The remote dataspace's SPARQL endpoint is discovered from the <code>Link</code> headers the proxy forwards, so views and charts over\n                remote documents query the <em>remote</em> endpoint</li>\n            <li>Writes are graph-scoped SPARQL updates (<code>PATCH</code>) or appends (<code>POST</code>) sent through the proxy under the origin's\n                <code>If-Match</code> precondition</li>\n            <li>Requests carry the delegated identity of the requesting agent, so the remote dataspace's <a href=\"../administration/acl/\">access control</a>\n                arbitrates every operation</li>\n        </ul>\n        <p>In the user interface this means you can <a href=\"../../user-guide/browse-data/\">browse</a> a remote dataspace and\n            <a href=\"../../user-guide/add-data/\">add data</a> to its documents the same way as to local ones, provided the remote access control allows it.</p>\n        <p>The example above uses the public demo hosts because they are reachable without any setup, but nothing about federation requires a second\n            instance: two <a href=\"../dataspace/#dataspaces\">dataspaces</a> on one LinkedDataHub are distinct origins, so the same exchange happens between\n            <samp>northwind-traders.demo.localhost:4443</samp> and <samp>unesco-thesaurus.demo.localhost:4443</samp> once both are\n            <a href=\"../../user-guide/manage-dataspaces/#create-dataspace\">declared</a>.</p>\n    </div>\n    <div>\n        <h2 id=\"system-endpoints\">System endpoints</h2>\n        <p>Endpoints that LinkedDataHub serves in addition to the document hierarchy. Paths are relative to the dataspace's base URI.</p>\n        <table>\n            <caption class=\"ac-vh\">System endpoints by path</caption>\n            <thead>\n                <tr>\n                    <th scope=\"col\">Path</th>\n                    <th scope=\"col\">Description</th>\n                </tr>\n            </thead>\n            <tbody>\n                <tr>\n                    <th colspan=\"2\" id=\"app-endpoints\" scope=\"rowgroup\">Admin and end-user apps</th>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>ns</samp></th>\n                    <td>In-memory namespace ontology as well as its SPARQL endpoint</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>sitemap.xml</samp></th>\n                    <td>The dataspace's public documents, in the <a href=\"https://www.sitemaps.org/protocol.html\" target=\"_blank\">sitemaps protocol</a>: generated at startup from the public read rules of the dataspace's own admin service, so an origin lists only its own documents. An end-user dataspace with nothing public has none, and neither does an admin dataspace</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>robots.txt</samp></th>\n                    <td>Allows crawling and names the sitemap when the dataspace has one; disallows everything when it has none</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>settings</samp></th>\n                    <td>The dataspace's own description in the dataspace configuration. <code>PATCH</code> with a SPARQL update edits it — this is how <a href=\"../administration/packages/\">packages</a> are installed and uninstalled. Editing is restricted to end-user dataspaces: a <code>PATCH</code> on an admin dataspace's settings answers <samp>422 Unprocessable Entity</samp></td>\n                </tr>\n            </tbody>\n            <tbody>\n                <tr>\n                    <th colspan=\"2\" id=\"admin-endpoints\" scope=\"rowgroup\">Admin app only</th>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>admin/access</samp></th>\n                    <td>Access metadata (for the authenticated agent)</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>admin/access/request</samp></th>\n                    <td>Access request (for the authenticated agent)</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>admin/sign%20up</samp></th>\n                    <td>WebID-TLS agent signup</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>oauth2/login/google</samp></th>\n                    <td>OpenID Connect with Google login</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>oauth2/login/orcid</samp></th>\n                    <td>OpenID Connect with ORCID login</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>oauth2/authorize/google</samp></th>\n                    <td>OpenID Connect with Google callback</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>oauth2/authorize/orcid</samp></th>\n                    <td>OpenID Connect with ORCID callback</td>\n                </tr>\n                <tr>\n                    <th scope=\"row\"><samp>admin/clear</samp></th>\n                    <td>Clears every cached ontology graph and imports closure from memory. With an optional <code>uri</code> form parameter, also purges that ontology's proxy caches and reloads its closure from the admin SPARQL endpoint</td>\n                </tr>\n            </tbody>\n        </table>\n    </div>\n    <div>\n        <h2 id=\"caching\">Caching</h2>\n        <p><code>GET</code> and <code>HEAD</code> RDF responses from the backend triplestores (<em>not LinkedDataHub responses</em>) are cached automatically by LinkedDataHub using <a href=\"https://varnish-cache.org\" target=\"_blank\">Varnish</a>\n            as an HTTP proxy cache. You can check the age of the response by inspecting the <code>Age</code> response header (the value is in seconds).</p>\n        <p>LinkedDataHub sends <code>ETag</code> response headers derived from a digest of the document's URL and its RDF content. Every representation (HTML, RDF/XML, Turtle, etc.) gets a distinct <code>ETag</code> value, and language-negotiated HTML representations factor the accepted languages into the tag. Treat the value as opaque: it is a validator to quote back in a <a href=\"#preconditions\">conditional request</a>, and nothing about the document can be read from it.</p>\n        <p>HTML responses carry a <code>Content-Language</code> negotiated against the languages the UI ships with, and advertise <code>Vary: Accept-Language</code> so shared caches keep the renderings apart.</p>\n        <p>Caching of LinkedDataHub responses can be enabled on the nginx HTTP proxy server by uncommenting the <code>add_header Cache-Control</code> directives in the <samp>platform/nginx.conf.template</samp> file.\n            Caching of <samp>/uploads/</samp> and <samp>/static/</samp> namespaces is enabled by default.</p>\n    </div>\n</div>"^^<http://www.w3.org/1999/02/22-rdf-syntax-ns#XMLLiteral>;
        <http://www.w3.org/2000/01/rdf-schema#seeAlso>
                <https://www.w3.org/TR/sparql11-http-rdf-update/> .

<https://docs.linkeddatahub.com/reference/http-api/>
        a       <https://w3id.org/atomgraph/linkeddatahub/document-hierarchy#Item>;
        <http://www.w3.org/1999/02/22-rdf-syntax-ns#_1>
                <https://docs.linkeddatahub.com/reference/http-api/#content>;
        <http://purl.org/dc/terms/created>
                "2026-09-29T09:52:22.96Z"^^<http://www.w3.org/2001/XMLSchema#dateTime>;
        <http://purl.org/dc/terms/creator>
                <https://admin.linkeddatahub.com/acl/agents/5ba81960-d511-4a3b-8b9a-cb5bb278dd95/#this>;
        <http://purl.org/dc/terms/description>
                "Read and write RDF data from and to LinkedDataHub dataspaces over HTTP";
        <http://purl.org/dc/terms/title>
                "HTTP API";
        <http://rdfs.org/sioc/ns#has_container>
                <https://docs.linkeddatahub.com/reference/>;
        <http://www.w3.org/ns/auth/acl#owner>
                <https://admin.linkeddatahub.com/acl/agents/5ba81960-d511-4a3b-8b9a-cb5bb278dd95/#this> .
