Annotations - W3C Web Annotation support
Heratio stores annotations using the
W3C Web Annotation Data Model
and exposes them via the
Web Annotation Protocol (WAP)
on the /api/annotations surface. This article covers what you can target,
what you can annotate with, and how third-party tools interact with the
endpoint.
What can I annotate?
| Target type | Selector | Use case |
|---|---|---|
| IIIF canvas region | FragmentSelector (xywh=x,y,w,h) |
Mark a region on a scanned page or image |
| Freeform shape | SvgSelector |
Mirador-annotation-editor drawings |
| Text quote | TextQuoteSelector (exact + prefix/suffix) |
Anchor a comment to a specific phrase |
| Text position | TextPositionSelector (start + end) |
Pin to character offsets |
| Audio / video range | TimeSelector (npt=0.0,10.0) or MediaFragmentSelector (t=0,10) |
Comment on a time range in a media file |
| Geographic point | GeoSelector / PointSelector (WKT) |
Pin an annotation to a map coordinate |
| HTML region | RangeSelector / CssSelector / XPathSelector |
DOM-based anchoring |
You can combine selectors using the spec's refinedBy chain (e.g.
"the first paragraph, then the third sentence within it") and Heratio
will round-trip them losslessly.
Body shapes
- TextualBody - plain text comment.
- SpecificResource - point at an external resource, optionally with its own selector. Useful when you want to say "annotate the second paragraph of this URL with a tag from this vocabulary".
- Multiple bodies - the spec allows an array of bodies; Heratio stores it verbatim.
Example SpecificResource body:
{
"type": "Annotation",
"motivation": "commenting",
"target": "https://heratio.host/iiif/3/<id>/canvas/1",
"body": {
"type": "SpecificResource",
"source": "https://example.org/source-doc",
"selector": {
"type": "TextQuoteSelector",
"exact": "the quick brown fox"
}
}
}
REST endpoints
| Verb | Path | Auth |
|---|---|---|
| GET | /api/annotations/search?targetId=<canvas> |
public |
| GET | /api/annotations/{uuid} |
public |
| POST | /api/annotations |
session |
| PUT | /api/annotations/{uuid} |
session |
| DELETE | /api/annotations/{uuid} |
session |
All responses use Content-Type: application/ld+json; profile="http://www.w3.org/ns/anno.jsonld"
and carry the WAP Link header advertising LDP resource + WAP
constrainedBy.
Container preferences
The search endpoint honours Prefer (RFC 7240). Pass
Prefer: return=representation; include="http://www.w3.org/ns/oa#PreferContainedIRIs"
to receive a list of annotation IRIs in first.items instead of full
annotation envelopes. The response advertises the applied preference in
Preference-Applied.
Optimistic concurrency
Every individual annotation carries an ETag. To safely edit:
GET /api/annotations/{uuid}and read theETagheader.PUT /api/annotations/{uuid}withIf-Match: "<etag>". If the annotation changed since you read it, the server returns 412 Precondition Failed with the current ETag in the response body so you can re-fetch and resolve.
GET with If-None-Match: "<etag>" returns 304 Not Modified when the
annotation is unchanged - useful for caching.
Clients
- Mirador-annotation-editor is wired into the Heratio Mirador viewer
via
HeratioAnnotationAdapter(intools/mirador-build/src/index.js). Drawing with MAE saves SVG selectors which are read back by Mirador's stock canvas overlay. - Any WAP-conformant client (Hypothesis, Annotorious 3, custom code) can talk to the endpoint directly. Use the W3C envelope and standard Web Annotation JSON-LD shape.
- Annotot-shaped clients read the legacy
resourcesarray which remains alongside the W3C-specfirst.itemsshape.
Auth
Reads are public. Writes require an authenticated session. Anonymous writes receive a JSON 401 (not a 302 redirect) so single-page clients can surface a real error rather than a confusing HTML response.
/api/annotations* is exempt from Laravel CSRF: the session-auth gate
already blocks cross-site forgery.
Compliance roadmap (issue #648)
- Phase 1 (current) - W3C Data Model + WAP REST conformance.
- Phase 2 - Threading (annotation replies).
- Phase 3 - Moderation queue (pending / approved / rejected).
- Phase 4 - Revisions + consolidation across legacy annotation surfaces.