Skip to content

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.

sh
# Search within a site (returns public items only)
curl 'https://archivebase.ldas.jp/{account}/{db}/api/search?q=term'

Quickstart (curl)

sh
KEY="ak_xxxxxxxx.yyyyyyyyyyyy"          # issued in the dashboard
BASE="https://archivebase.ldas.jp"
ACC="your-account"

Create a database (library)

sh
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)

sh
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)

sh
curl -s "$BASE/$ACC/nishikie/api/search?q=Kuniyoshi&facet=placeName"

Common endpoints

MethodPathScopePurpose
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/databasewriteUpdate 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/resourcesreadList (type / parent / page[...])
POST/{account}/{db}/api/resourceswriteCreate
GET/{account}/{db}/api/resources/{id}readFetch (by slug or uuid); ?format=jsonld etc. exports LOD (below)
PATCH/{account}/{db}/api/resources/{id}writePartial update
DELETE/{account}/{db}/api/resources/{id}writeDelete
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/importwriteCSV bulk import (Omeka CSVImport-compatible)
POST/{account}/{db}/api/uploadswriteIssue a presigned S3 PUT URL for a binary; derivative:'ptif' enters the IIIF image pipeline (below)
POST/api/{account}/uploads/{asset}/finalizewriteEnqueue a tiled upload for conversion (call after PUTting the source)
GET/api/{account}/uploads/{asset}readPoll conversion state ({status, is_public, width, height, iiif})
PATCH/api/{account}/uploads/{asset}writeUpdate 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}/usagereadUsage

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.

formatContent
jsonldschema.org-based JSON-LD (Japan Search utilization-schema flavour). The default profile — works for any kind of material
ricoRiC-O (Records in Contexts) JSON-LD, expressing archival description: the hierarchy (fonds/series/file) and carriers (Instantiation)
ttl / rico-ttlTurtle serialization of either profile (for RDF tooling)
bash
# 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"
  • @id is 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:date ride through as-is, and canonical keys such as license map to their property (schema:license, …). Free-form keys that cannot be mapped are aggregated into schema:description as key: value lines, so no information is lost.
  • Hierarchy links use schema:isPartOf / schema:hasPart (in RiC-O rico: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.

bash
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 Accept header (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.

bash
# 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)
  • metadataPrefix is oai_dc (Dublin Core) or jps (Japan Search schema)
  • set is the resource type (item / collection …); enumerate them with ListSets
  • from / until give 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.

bash
# 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).

bash
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] (or page[limit] + page[offset]) — paging
  • sort=<key> — ordering; prefix with - for descending (sort=-year)
sh
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.

PathContents
/{account}/{db}/api/resourcesync/capabilitylist.xmlThe documents this site offers
/{account}/{db}/api/resourcesync/resourcelist.xmlEvery public resource as of now (split into ?p=N pages of 10,000)
/{account}/{db}/api/resourcesync/changelist.xmlChanges; 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).