Using the API
Every endpoint is listed and tryable in the Swagger UI. This page is a walkthrough; for the exhaustive reference see the Swagger UI and docs/API.md.
Authentication
API keys (for programs)
Write operations (creating and updating resources, etc.) and reads of private data require an API key. Keys belong to an account and carry read / write scopes.
Authorization: Bearer <public_id>.<secret>How to issue one:
- Dashboard /dashboard/keys (Google login) → "Issue a new key"
POST /api/me/keys(Firebase ID token)
The secret is shown once
A key's secret (.secret) is shown only once at issue time (the server stores only a sha256 hash). Save it somewhere safe (e.g. 1Password). If it leaks, revoke and reissue.
Reading public data needs no key
Listing, searching and fetching public (is_public) resources works without authentication.
# Search within a site (returns public items only)
curl 'https://archivebase.ldas.jp/{account}/{db}/api/search?q=term'Quickstart (curl)
KEY="ak_xxxxxxxx.yyyyyyyyyyyy" # issued in the dashboard
BASE="https://archivebase.ldas.jp"
ACC="your-account"Create a database (library)
curl -s -X POST "$BASE/api/$ACC/databases" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{"slug":"nishikie","title":"Nishikie Collection"}'Create a resource (item)
curl -s -X POST "$BASE/$ACC/nishikie/api/resources" \
-H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
-d '{
"slug":"0380-17-1",
"type":"item",
"title":"Doke musha zukushi",
"metadata":{"dcterms:creator":"Utagawa Kuniyoshi","year":"1858"}
}'Search (no key)
curl -s "$BASE/$ACC/nishikie/api/search?q=Kuniyoshi&facet=placeName"Common endpoints
| Method | Path | Scope | Purpose |
|---|---|---|---|
| GET | /api/accounts | (public / optional) | Catalog of libraries on the platform. Each db returns its service (dl/text/records) so you can build /{account}/{slug}. ?scope=mine (auth: session or API key) also lists your own private dbs; ?scope=all (admin only) lists every db |
| PATCH | /{account}/{db}/api/database | write | Update site settings. {settings:{service:'text'}} switches the serving app (dl/text/records) — the public URL changes and the old path 307s to the new one. card (site-listing card), provider (holding institution) and ogImage are settable with an API key too. Other display keys: see Swagger |
| GET | /{account}/{db}/api/resources | read | List (type / parent / page[...]) |
| POST | /{account}/{db}/api/resources | write | Create |
| GET | /{account}/{db}/api/resources/{id} | read | Fetch (by slug or uuid); ?format=jsonld etc. exports LOD (below) |
| PATCH | /{account}/{db}/api/resources/{id} | write | Partial update |
| DELETE | /{account}/{db}/api/resources/{id} | write | Delete |
| GET | /{account}/{db}/api/search | (public) | Search & facets |
| GET/POST | /{account}/{db}/api/oai | (public) | OAI-PMH 2.0 harvesting (below) |
| POST | /{account}/{db}/api/import | write | CSV bulk import (Omeka CSVImport-compatible) |
| POST | /{account}/{db}/api/uploads | write | Issue a presigned S3 PUT URL for a binary; derivative:'ptif' enters the IIIF image pipeline (below) |
| POST | /api/{account}/uploads/{asset}/finalize | write | Enqueue a tiled upload for conversion (call after PUTting the source) |
| GET | /api/{account}/uploads/{asset} | read | Poll conversion state ({status, is_public, width, height, iiif}) |
| PATCH | /api/{account}/uploads/{asset} | write | Update an asset (worker flips it ready / toggle per-image is_public) |
| GET | /api/{account}/iiif-img/3/{asset}/info.json | (public asset) | IIIF Image API (Cantaloupe proxy; the bare base URI 303s to info.json) |
| GET | /api/{account}/usage | read | Usage |
IIIF image pipeline: adding derivative:'ptif' to POST /uploads gives you presign → PUT → finalize → background libvips conversion to pyramidal TIFF → once GET /uploads/{asset} reports ready, the image serves through the IIIF Image API. Assets are account-owned and visibility is per-image (is_public). See the uploads / tenant-iiif tags in the Swagger UI for details.
LOD export (JSON-LD / RiC-O / Turtle)
Every resource can be fetched as LOD (Linked Open Data) via ?format= on GET /resources/{id}. Public resources need no key.
| format | Content |
|---|---|
jsonld | schema.org-based JSON-LD (Japan Search utilization-schema flavour). The default profile — works for any kind of material |
rico | RiC-O (Records in Contexts) JSON-LD, expressing archival description: the hierarchy (fonds/series/file) and carriers (Instantiation) |
ttl / rico-ttl | Turtle serialization of either profile (for RDF tooling) |
# schema.org JSON-LD (default profile)
curl "https://archivebase.ldas.jp/demo/library/api/resources/doc-1?format=jsonld"
# RiC-O as Turtle
curl "https://archivebase.ldas.jp/demo/library/api/resources/doc-1?format=rico-ttl"@idis the data URI/{account}/{db}/data/{id}— the unique URI of the thing itself. Fetched programmatically it returns JSON-LD/Turtle; opened in a browser it 303-redirects to the item's detail page (/resource/{id}) — the same convention as Wikidata and Japan Search.- Metadata keys are mapped to RDF properties: CURIE keys such as
dcterms:dateride through as-is, and canonical keys such aslicensemap to their property (schema:license, …). Free-form keys that cannot be mapped are aggregated intoschema:descriptionaskey: valuelines, so no information is lost. - Hierarchy links use
schema:isPartOf/schema:hasPart(in RiC-Orico:isOrWasIncludedIn/rico:hasInstantiation, …) and only reference resources within the caller's visibility. - The item detail page's share rail also links "LOD (JSON-LD)" (and "RiC-O" on sites with archival arrangement configured).
SPARQL endpoint
Sites with the rdf setting enabled keep an RDF graph of all their public resources (schema.org + RiC-O) in a triplestore and expose a read-only SPARQL endpoint. No key is required.
curl -G "https://archivebase.ldas.jp/api/demo/dl/library/sparql" --data-urlencode 'query=
PREFIX schema: <https://schema.org/>
SELECT ?s ?name WHERE { ?s schema:name ?name } LIMIT 10'- The default graph is that site's graph;
GRAPH ?g { … }can query across other public sites (the store only ever contains public resources). - Pick the result format with the
Acceptheader (JSON / XML / CSV / Turtle). - Site admins (re)build the graph in bulk with
POST …/rdf-index.
OAI-PMH (bulk harvesting)
Public sites act as OAI-PMH 2.0 providers. This is the standard way to let an aggregator (Japan Search, for example) collect a site's metadata in bulk.
# Repository information
curl "https://archivebase.ldas.jp/{account}/{db}/api/oai?verb=Identify"
# Everything, as Dublin Core
curl "https://archivebase.ldas.jp/{account}/{db}/api/oai?verb=ListRecords&metadataPrefix=oai_dc"
# Everything, as the Japan Search schema (RDF/XML)
curl "https://archivebase.ldas.jp/{account}/{db}/api/oai?verb=ListRecords&metadataPrefix=jps"- All six verbs are supported (
Identify/ListMetadataFormats/ListSets/ListIdentifiers/ListRecords/GetRecord) metadataPrefixisoai_dc(Dublin Core) orjps(Japan Search schema)setis the resource type (item/collection…); enumerate them withListSetsfrom/untilgive you incremental harvesting by update date- Continue with
resumptionToken. There is no cap on how much you can fetch - Only public resources of public sites are exposed; private sites return 404
Protocol errors come back as HTTP 200
Per the OAI-PMH spec, bad arguments and the like are reported in the body as <error code="...">, not via the HTTP status. Do not treat HTTP 200 alone as success.
Authorities (entities) and query expansion
You can register account-wide authority records (people, places, organizations, …). Each entity carries entityType + multilingual prefLabel + altLabels (spelling variants / transliterations) + sameAs (Wikidata / GeoNames URIs). Reading needs no key.
# Create an authority (owner key)
curl -s -X POST "$BASE/api/$ACC/entities" -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" -d '{"slug":"nagasaki","entityType":"place","prefLabel":{"ja":"長崎","en":"Nagasaki"},"altLabels":["Nangazackische"],"sameAs":["http://www.wikidata.org/entity/Q38620"],"coordinates":{"lat":32.7448,"lon":129.8737}}'
# The authority as LOD
curl -s "$BASE/api/$ACC/entities/nagasaki?format=jsonld"Query expansion: add &expand=entities to a search and, when the query matches an authority label, the search ORs across all its labels including altLabels. Searching for 長崎 then also hits transcriptions that only contain the Dutch spelling Nangazackische (the response's expanded field lists the labels used).
curl -s "$BASE/$ACC/voc/api/search?q=長崎&expand=entities"Resource LOD (?format=jsonld and /data/{id}) also auto-links mentions: when a metadata value matches an authority label, the output carries schema:about pointing at that authority.
Authorities can also be managed in the dashboard's "Authorities" page (list / create / edit / delete, plus a map of place authorities).
Search query (JSON:API style)
/search accepts:
q— search terms (websearch syntax)facet=<key>— metadata key(s) to aggregate (repeatable)filter[<key>]=<value>— filter by metadata (repeat the same key for OR)page[number]+page[size](orpage[limit]+page[offset]) — pagingsort=<key>— ordering; prefix with-for descending (sort=-year)
curl 'https://archivebase.ldas.jp/{account}/{db}/api/search?q=Hokusai&filter[persName]=Katsushika+Hokusai&page[size]=20&sort=-year'Legacy params are deprecated
limit / offset / dir and bare metadata params are deprecated (marked as such in Swagger). New code should use page[...] / filter[...] / sort=-<key>.
Access control and errors
- Private databases and items return 404 to unauthorised requests (their existence is not revealed)
- Writes to another account's resources return 403 (insufficient scope)
- Anonymous access to authenticated endpoints returns 401
- Duplicate slug is 409, quota exceeded is 402, single-upload size overflow is 413
Errors are returned as JSON { "error": "..." }.
Custom domains
A public site can be served under a custom host name (Vercel-style — rewritten to the tenant internally, the address bar keeps the host). Two kinds: an *.ldas.jp subdomain (served immediately) or a customer-owned external domain (Cloudflare for SaaS — set the returned CNAME/TXT, then {host,verify:true} to validate and go live). Both are public-DBs-only and flow through the CF edge, so the WAF applies. Manage it with the Firebase-session GET/POST/DELETE /api/me/domains (or the dashboard → site detail → "Custom domain"). See the Swagger UI and the user guide.
Bulk import
- CSV (Omeka CSVImport-compatible) — from the dashboard's site detail, or
POST /dl/{db}/import - dcb format — an importer for
collection.csv/item.csv/media.csv/annotation.csv(npm run import:dcb)
Work in progress
Details of API-key scope design, rate limits, and whether webhooks / harvesting (OAI-PMH, etc.) are supported are yet to be documented.
ResourceSync (synchronisation)
To mirror a public site's contents into another system, use ResourceSync (ANSI/NISO Z39.99-2017). It is an extension of the Sitemap protocol and needs no authentication.
Start at https://archivebase.ldas.jp/.well-known/resourcesync (on a custom domain, https://<that host>/.well-known/resourcesync). From there you can reach each site's Capability List.
| Path | Contents |
|---|---|
/{account}/{db}/api/resourcesync/capabilitylist.xml | The documents this site offers |
/{account}/{db}/api/resourcesync/resourcelist.xml | Every public resource as of now (split into ?p=N pages of 10,000) |
/{account}/{db}/api/resourcesync/changelist.xml | Changes; narrow the window with ?from=2026-01-01T00:00:00Z |
Each entry's <loc> points at the machine-readable representation (the LOD data URI /{account}/{db}/data/{id}, which serves schema.org JSON-LD by default); the human-facing page is given alongside it as <rs:ln rel="alternate">. Change types are created / updated only — deletions are not reported. Sites backed by Elasticsearch or federated search have no modification timestamps and are therefore not supported (404).