Skip to content

Oxton Research Identifier · persistent identifiers and open metadata for scholarly publications

ORI — Oxton Research Identifier Oxton Research Identifier
Menu

Guide

API documentation

The ORI API is versioned under /wp-json/ori/v1/. Read endpoints are public and return only public records. Write endpoints require a journal credential and act only on that journal. Every call goes through the same validation, permissions and audit as the dashboard. Any approved journal can integrate its own editorial system directly: no connector or plugin is required, and issuing identifiers is free.

Updated outubro 16, 2026

Full specification: OpenAPI 3.1 (openapi.yaml).

Public read endpoints

EndpointReturns
GET /recordsPublic records, newest first. Parameters: page, per_page (up to 100), journal, year, status.
GET /records/{identifier}The full public record.
GET /resolve/{identifier}Status, record URL, article URL and DOI.
GET /searchSearch with q and the portal filters (journal, year, status, lang, type, sort); results and facets.
GET /journals, GET /journals/{id}Participating journals.

Listings return the totals in the X-WP-Total and X-WP-TotalPages headers. Requests are limited to 120 per minute per client; above the limit the API answers 429 Too Many Requests.

curl https://oriregistry.org/wp-json/ori/v1/resolve/10001/2026.0001

{"identifier":"ORI:10001/2026.0001","status":"published","record_url":"https://oriregistry.org/10001/2026.0001","article_url":"https://journal.example.org/article/1","doi":null}

Authentication

An institutional administrator issues a credential for the journal in the ORI dashboard (Credentials); the secret is shown only once. Credentials are accepted only over HTTPS. There are two ways to use it:

  • Signed requests (recommended): each request carries X-ORI-Key, X-ORI-Timestamp, X-ORI-Nonce and X-ORI-Signature; the secret never travels. A credential can be set to accept signed requests only.
  • Bearer token: Authorization: Bearer ori_…, or X-ORI-Credential on servers that remove the Authorization header.
ScopeAllows
registrations:writeSend registration requests and deposit files of registered records.
registrations:readFollow registration requests.
records:writeCreate and update records directly and change their status.
records:readRead the records of the journal, including drafts and reservations.
records:statusOptional: withdraw or retract records of the journal, always with a reason.

Signed requests

The token has the form ori_<key>_<secret>. Send the key in X-ORI-Key, the current Unix time in X-ORI-Timestamp (accepted within 5 minutes), a new random value of 16 to 64 letters, digits, - or _ in X-ORI-Nonce (each nonce is accepted once) and, in X-ORI-Signature, the hexadecimal HMAC-SHA256 of the following lines, keyed with the secret:

METHOD                       e.g. POST



route                        the path after /wp-json, e.g. /ori/v1/registrations



query                        parameters sorted by name, RFC 3986 (empty line when none)



timestamp                    the X-ORI-Timestamp value



nonce                        the X-ORI-Nonce value



sha256(body)                 hexadecimal SHA-256 of the exact body sent (of "" when none)

Credentials issued before signed requests were available work as Bearer tokens; rotate them to sign requests.

Limits, request id and rotation

  • Each credential may send up to 300 requests per minute (and each client address 120 per minute on the public endpoints); above the limit the answer is 429 with Retry-After.
  • Every answer carries X-Request-Id (yours, when you send one, or a new one). Quote it when reporting a problem.
  • Rotate a credential in the dashboard: a new secret is issued at once and the previous one keeps working for 1 or 7 days (or stops immediately), so the editorial system can be updated without interruption.
  • Requests and errors of each credential in the last 30 days are shown in the dashboard. Credentials stop working when the journal or its organization is suspended.

GET /me returns the credential, its journal, its scopes and what the plan of the organization allows.

  1. Check first (optional): POST /registrations?validate_only=1 with the same body runs every check (metadata, permissions, duplicates) and writes nothing; it answers {"valid": true, "request_type": "create" | "update", "identifier": …} or the errors.
  2. Reserve during production: after acceptance, POST /registrations with "target_status": "reserved" and an Idempotency-Key header, so retries are safe. The identifier is definitive: print it in the proofs and in the PDF. A reserved record is not public and is not in the repository.
  3. Confirm the publication: when the article is out, send the same source_ref with "target_status": "published", the publication date and the article address. The reserved identifier is kept; no other is issued. The record becomes public and enters the ORI Research Repository automatically.
  4. Read the answer: 200 with status completed and the identifier, or 202 with status pending when the journal reviews registrations.
  5. Follow pending requests: GET /registrations/{id} — pending, completed (with the identifier), rejected or failed (with the errors).
  6. Keep it up to date: when record.source_ref matches an article already registered by the journal, the request updates it; the identifier never changes. Simultaneous requests for the same article never create a second record.
curl -X POST https://oriregistry.org/wp-json/ori/v1/registrations \
  -H "Authorization: Bearer ori_…" -H "Idempotency-Key: article-123" -H "Content-Type: application/json" \
  -d '{"target_status":"published","record":{"source_ref":"article-123","publication_type":"research-article","language":"en","title":"…","contributors":[{"given_names":"Ana","family_name":"Souza"}],"published_date":"2026-10-01","article_url":"https://journal.example.org/article/123"}}'

Direct record endpoints

EndpointWhat it does
POST /recordsCreate a record (draft, reserved or published).
GET /records/{identifier or uuid}Read a record of the journal, including drafts.
PATCH /records/{identifier or uuid}Update metadata. Requires If-Match: <version>; an outdated version answers 412.
POST /records/{identifier or uuid}/statusBody {"status": "reserved" | "published" | "withdrawn" | "retracted", "reason": "…"}. Withdrawal and retraction need the records:status scope and a reason, shown on the public page.
POST /records/{identifier}/filesDeposit a file (multipart: file, kind, version, embargo_until, label); the answer gives its SHA-256.

Journals that require approval cannot issue identifiers through direct endpoints; they use registration requests. A correction or an expression of concern is registered as a new record of that type, related to the corrected record (relations).

Errors

StatusMeaning
401Missing or invalid credential (ori_unauthorized); signed requests: ori_invalid_signature, ori_stale_timestamp, ori_replay, ori_signature_required, ori_signing_unavailable.
403Not allowed: missing scope (ori_forbidden) or credential sent without HTTPS (ori_https_required).
404Not found, also for records of other journals.
409Conflict: duplicate (the message gives the existing ORI) or invalid status change.
412 / 428Outdated version / missing If-Match.
422Invalid metadata, with the errors per field.
429Too many requests.

Errors return JSON with code, message and data.status; validation errors add data.errors per field. Server errors (500) include data.request_id.

OAI-PMH

Aggregators, indexers and libraries can harvest every public record through OAI-PMH 2.0 at https://oriregistry.org/oai (GET or POST).

  • Verbs: Identify, ListMetadataFormats, ListSets, ListIdentifiers, ListRecords and GetRecord.
  • Metadata format: oai_dc (Dublin Core), with the info:eu-repo vocabularies for type, version and access rights.
  • Item identifiers: oai:oriregistry.org:ORI:10001/2026.0001.
  • Sets: journal:{journal} for each participating journal and type:{publication type}.
  • Selective harvesting with from and until (day or second granularity, UTC). Large lists are paged with resumption tokens (50 records or 200 identifiers per response).
  • Withdrawn records remain as deleted headers for ever (deletedRecord: persistent); drafts and reservations are never exposed.
https://oriregistry.org/oai?verb=ListRecords&metadataPrefix=oai_dc&set=journal:zoom-business-review

Other guides