HTTP + JSON
REST endpoints
A small, opinionated REST surface alongside the GraphQL endpoint. Useful for build-time scripts, static-site generators, and pipelines that prefer plain HTTP over a query language.
Interactive reference
Prefer an interactive viewer with a live key verifier?
The /implement/api-reference page renders every /api/v1/* endpoint as a card with parameters, status codes, curl examples, and a paste-your-key panel that verifies against GET /api/v1/me. The full OpenAPI 3.1 specification is served from /api/v1/openapi.jsonand is ready for openapi-generator, Stainless, Speakeasy, Fern, or any OAS 3.1 toolchain.
Namespace
All CASRAI REST endpoints live under a single namespace served by the WordPress REST API. The full root URL is:
https://casrai.org/wp-json/casrai/v1/
http://localhost/casrai/wp/wp-json/casrai/v1/
The REST surface is a deliberately narrow companion to the GraphQL endpoint. Where GraphQL is preferred for ad-hoc field selection and federated traversal, the REST endpoints provide stable, cacheable URLs suitable for static builds and curl-driven workflows.
Authentication
Read endpoints are public. Write endpoints accept WordPress Application Passwords using HTTP Basic authentication (see the WordPress documentation on Application Passwords, introduced in 5.6). Application Passwords are issued per-user from the WordPress admin and can be revoked individually.
Note which is which: within the casrai/v1 namespace, /dictionary-term, /object-template and /picklist are write-only upsert helpers — they register a POST handler only and reject anonymous callers with 401 rest_forbidden. The public readers in this namespace are /dictionary/stats and /dictionary/term-index; to read terms, templates and picklists anonymously, use the WordPress core routes shown in each section below.
Authorization: Basic $(echo -n "username:application_password" | base64)
Endpoint: /dictionary-term (write only)
This route is an authenticated upsert helper, not a public reader. It accepts POST only; an unauthenticated request returns 401 rest_forbidden, and there is no GET handler registered on it. Use it to create or update a dictionary term, authenticating with an Application Password as shown above.
curl -sS -X POST "https://casrai.org/wp-json/casrai/v1/dictionary-term" \
-u "username:application_password" \
-H "Content-Type: application/json" \
-d '{ "slug": "research-integrity", "title": "Research integrity" }'To read terms without credentials, use the WordPress core route for the dictionary_term post type, which is public and supports slug lookup, paging, and domain filtering. The record it returns carries the operational definition, examples, counter-examples, aliases, canonical URI, status, and version.
curl -sS "https://casrai.org/wp-json/wp/v2/dictionary_term?slug=research-integrity" \ -H "Accept: application/json"
{
"id": 4218,
"slug": "genai-disclosure",
"title": "GenAI disclosure",
"status": "stable",
"version": "v2026.1",
"canonical_uri": "https://casrai.org/dictionary/genai-disclosure",
"definition_operational": "A structured statement attached to a research output declaring the use of generative AI tools, the model and version, the human author's role, and the scope of AI-assisted content.",
"examples": ["Manuscript declares use of GPT-4 for copy-editing."],
"counter_examples": ["Author lists 'ChatGPT' as a co-author."],
"aliases": ["AI disclosure", "Generative AI statement"],
"dictionary_domains": [
{ "slug": "genai-disclosure", "name": "GenAI disclosure", "track": "core" }
],
"relationships": [
{ "type": "related", "target_slug": "authorship", "note": "Co-located disclosure block" }
]
}Listing supports paging via per_page (default 20, max 100) and page, and a dictionary_domain query parameter that filters by domain. That filter takes the domain's numeric term id, which you can resolve from its slug via the dictionary_domain route.
# resolve the domain slug to its term id curl -sS "https://casrai.org/wp-json/wp/v2/dictionary_domain?slug=genai-disclosure&_fields=id,slug" # then list that domain's terms curl -sS "https://casrai.org/wp-json/wp/v2/dictionary_term?dictionary_domain=16&per_page=50&page=1"
For a cheap, complete slug/title index of every term in one response, the CASRAI namespace does expose a public reader: GET /wp-json/casrai/v1/dictionary/term-index.
curl -sS "https://casrai.org/wp-json/casrai/v1/dictionary/term-index"
Endpoint: /object-template (write only)
Object templates describe composite metadata records — a Person record, a Project record, a Grant record — as ordered sets of fields. Each field declares a name, a primitive type, a required flag, and either a picklist slug or a dictionary term slug for its value space.
Like /dictionary-term, this route is an authenticated POST upsert helper with no public GET handler. Read object templates through the WordPress core route instead.
curl -sS "https://casrai.org/wp-json/wp/v2/object_template?slug=working-paper"
{
"id": 8842,
"slug": "person-affiliation",
"title": "Person affiliation",
"canonical_uri": "https://casrai.org/dictionary/object/person-affiliation",
"legacy_source": "CASRAI dictionary v1 (2018)",
"fields": [
{ "name": "person", "type": "reference", "required": true, "dictionary_term_slug": "person" },
{ "name": "organisation","type": "reference", "required": true, "dictionary_term_slug": "organisation" },
{ "name": "role", "type": "enum", "required": false, "picklist_slug": "affiliation-role-types" },
{ "name": "start_date", "type": "date", "required": false },
{ "name": "end_date", "type": "date", "required": false }
]
}Endpoint: /picklist (write only)
Picklists are controlled value sets — countries, language codes, contributor types, output types — that constrain a field on an object template. Each list returns its values as an array of strings (or string/identifier pairs where the picklist is identifier-backed).
This route is the authenticated POST upsert helper for picklists; it has no public GET handler. Read picklists through the WordPress core route.
curl -sS "https://casrai.org/wp-json/wp/v2/picklist?slug=output-types"
{
"id": 6112,
"slug": "output-types",
"title": "Research output types",
"canonical_uri": "https://casrai.org/dictionary/picklist/output-types",
"legacy_source": "COAR Resource Types v3.1 cross-walk",
"picklist_values": [
"Journal article",
"Book chapter",
"Conference paper",
"Dataset",
"Software",
"Preprint",
"Thesis",
"Report"
]
}Endpoint: /dictionary/stats
A small read-only endpoint returning counts and the last-modified timestamp for the dictionary as a whole. Useful for status badges, cache-warming scripts, and dashboard widgets that need a cheap "did anything change?" probe.
curl -sS "https://casrai.org/wp-json/casrai/v1/dictionary/stats"
{
"plugin_version": "2026.1",
"dictionary_term_count": "746",
"picklist_count": "211",
"object_template_count": "96",
"dictionary_domain_count": "20"
}Caching and rate limits
Read endpoints set Cache-Control: public, max-age=300, s-maxage=900 and emit an ETag per response. The Cloudflare edge in front of the origin honours both. Default rate limit is 60 requests per minute per IP for unauthenticated clients and 300 per minute per token for authenticated ones; the limits match those documented on the GraphQL endpoint.
Errors
The endpoints return standard HTTP status codes and a JSON error body shaped like the WordPress REST API: { "code": "...", "message": "...", "data": { "status": 404 } }.
API v1 Reference
The /api/v1/ namespace is the bearer-gated companion to the public WP REST surface above. All seven endpoints share a single authentication scheme (HTTP Bearer using a CASRAI plaintext key issued from Account → API keys), a single rate limit (60 requests per minute per key, sliding 60-second window), and a single response style (JSON with explicit X-RateLimit-* headers on every reply).
https://casrai.org/api/v1/
Authorization: Bearer casrai_pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Authentication errors
401 missing_authorization— noAuthorizationheader was sent.401 invalid_key_format— the bearer token does not start withcasrai_pk_.401 invalid_or_revoked_key— the key hash does not match any active key.403 insufficient_scope— the endpoint requireswritebut the key isread.429 rate_limit_exceeded— more than 60 requests in the rolling minute. InspectRetry-After.503 auth_backend_unavailable— the verification backend (WP) is temporarily unreachable.
GET /api/v1
Discovery document. Authentication is optional — sending a valid key returns an authenticated block reflecting the resolved identity.
curl https://casrai.org/api/v1
GET /api/v1/me
Returns { user_id, orcid_id, scope, key_prefix, api_version } for the key on the request.
curl -H "Authorization: Bearer $CASRAI_API_KEY" \
https://casrai.org/api/v1/me{
"user_id": 1429,
"orcid_id": "0000-0002-1825-0097",
"scope": "read",
"key_prefix": "casrai_pk_a3f201bc",
"api_version": "v1"
}GET /api/v1/credit/roles
Lists all 14 CRediT roles in canonical order (ANSI/NISO Z39.104-2022).
curl -H "Authorization: Bearer $CASRAI_API_KEY" \
https://casrai.org/api/v1/credit/roles{
"version": "v2022.1",
"standard": "ANSI/NISO Z39.104-2022",
"license": "CC-BY-4.0",
"count": 14,
"roles": [
{
"slug": "conceptualization",
"name": "Conceptualization",
"definition": "Ideas; formulation or evolution of overarching research goals and aims.",
"group": "Planning & design",
"order": 1
}
]
}GET /api/v1/credit/roles/{slug}
Returns a single CRediT role with its canonical URI. 404 if the slug is not one of the 14 NISO roles.
curl -H "Authorization: Bearer $CASRAI_API_KEY" \
https://casrai.org/api/v1/credit/roles/conceptualizationGET /api/v1/dictionary/terms
Paginated list of dictionary terms. Optional query parameters: domain (slug exact-match), limit (1–100, default 20), offset (default 0), search (substring match on slug and title, case-insensitive). Results are returned in deterministic alphabetical order by slug to make pagination stable.
curl -H "Authorization: Bearer $CASRAI_API_KEY" \
"https://casrai.org/api/v1/dictionary/terms?domain=knowledge-equity&limit=20&offset=0"{
"count": 47,
"limit": 20,
"offset": 0,
"results": [
{
"slug": "open-access",
"title": "Open access",
"domain_slug": "knowledge-equity",
"domain_name": "Knowledge equity",
"track": "core",
"status": "stable",
"operational_definition": "...",
"canonical_uri": "https://casrai.org/dictionary/term/open-access"
}
],
"filters": { "domain": "knowledge-equity", "search": null }
}GET /api/v1/dictionary/terms/{slug}
Full term record including examples, counter-examples, aliases, status, version, domain, and relationships.
curl -H "Authorization: Bearer $CASRAI_API_KEY" \
https://casrai.org/api/v1/dictionary/terms/genai-disclosureGET /api/v1/contributions
Lists the bearer key owner's previously-claimed CRediT contributions, sourced from the ORCID-linked WordPress record.
curl -H "Authorization: Bearer $CASRAI_API_KEY" \
https://casrai.org/api/v1/contributionsPOST /api/v1/contributions
Creates a CRediT contribution claim against the bearer key owner's ORCID iD. Requires the write scope — a read-only key returns 403 insufficient_scope. Roles must be a non-empty subset of the 14 CRediT slugs (see /api/v1/credit/roles).
curl -X POST https://casrai.org/api/v1/contributions \
-H "Authorization: Bearer $CASRAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"doi": "10.1234/example.2026.0001",
"title": "An open standards approach to research administration",
"journal": "Research Policy",
"date_published": "2026-04-12",
"roles": ["conceptualization", "writing-original-draft"]
}'{
"ok": true,
"user_id": 1429,
"orcid_id": "0000-0002-1825-0097",
"contribution": {
"put_code": 123456,
"doi": "10.1234/example.2026.0001",
"roles": ["conceptualization", "writing-original-draft"],
"pushed_at": "2026-05-21T11:14:02Z"
}
}Rate-limit headers
Every /api/v1/* response includes:
X-RateLimit-Limit— fixed at60.X-RateLimit-Remaining— requests remaining in the current 60-second window.X-RateLimit-Reset— Unix timestamp at which the window resets.Retry-After— seconds until retry, on429only.
CORS
The v1 endpoints set Access-Control-Allow-Origin: * and accept Authorization and Content-Type headers across origins. Pre-flight OPTIONS returns 204. All responses are application/json with charset=utf-8.
When to prefer REST over GraphQL
- Build-time fetches in a static site generator that does not bundle a GraphQL client.
- Shell pipelines or CI jobs driven by curl and jq.
- Edge functions where a small, cacheable URL outperforms a POST body.
- Status badges, smoke tests, and uptime probes against
/dictionary/stats.
For everything else — selecting nested fields, traversing relationships in a single round-trip, writing or proposing terms — see the GraphQL endpoint, the code examples, and the wider WordPress REST API reference.







