Skip to content

Indexer API

The Cabdell indexer reads the contract’s events from the Algorand blockchain, fetches and checks the content from IPFS, and serves what it knows as a read-only JSON API. The web app is built on it, and anyone can use it. It is a cache: everything it returns can be rebuilt from the chain and IPFS (see Verify without trusting cabdell.press and Run an indexer).

The routes below come from projects/indexer/src/api.ts, the code that answers them. Terms such as CID, round and address are explained in the Glossary.

One indexer runs per network, each with its own database and its own base URL, the indexerApi of the network in spec/networks.json. Data of different networks is never mixed.

Network Base URL
TestNet https://api.cabdell.press/testnet
MainNet not open yet; its base URL will be the indexerApi of the mainnet entry once it opens
LocalNet (your machine) http://localhost:3000
Terminal window
curl https://api.cabdell.press/testnet/status
  • Methods: GET and HEAD. OPTIONS answers 204 for browsers; any other method answers 405.

  • Responses are JSON (application/json; charset=utf-8), with Access-Control-Allow-Origin: *. Public answers that change little may be cached: /fields, /journals, /withheld and /cite answer Cache-Control: public, max-age=30, /status 10 seconds, the feed, article pages (with their comments, reviews, citations, jury, settleable) and /search/* 15 seconds, each with a weak ETag (If-None-Match answers 304). Everything per address or per viewer, /names, /activity, /notifications, /health and every error answer Cache-Control: no-store.

  • Envelope. Every response, errors included, starts with network and appId. Check them: they tell you which network and which application the data belongs to.

    { "network": "testnet", "appId": 773893388, "...": "the route's own fields" }
  • Addresses are 58-character Algorand addresses. CIDs are base32 text (bafybei... for articles, bafkrei... for reviews and comments). Times are Unix seconds (block time).

  • Field ids are numbers (771); some lists add hex (0x0303). Parameters called field accept either form.

  • type and status accept names or numbers. Types: article, notes, amendment, dataset, replication. Statuses: preprint, under_review, final, disputed, retracted (status 3, final, is shown in the app as “closed version”).

  • Boolean parameters accept 1, true, yes, on and 0, false, no, off.

  • List parameters of the search routes may be repeated or comma-separated: field=0x0303&field=0x0501 or field=0x0303,0x0501.

Code When Body
200 success the route’s fields
400 a parameter is invalid (the message names it); an ORCID iD with a wrong check character; a wildcard or regular expression that takes too long {"network", "appId", "error"}
404 unknown route; article or list not found same
405 a method other than GET, HEAD or OPTIONS same
500 an unexpected failure ("internal error"; the indexer logs it) same
503 /health when ingestion has stalled; searches with wildcards or regular expressions when their shared time budget is used up same
Terminal window
curl -i "https://api.cabdell.press/testnet/articles?sort=top"
# HTTP/1.1 400 ...
# {"network":"testnet","appId":773893388,"error":"sort must be score or new"}

The indexer applies no per-client rate limit. Lists are paged with limit and offset, or with a cursor where noted:

Route Paging Default Range
/articles limit, offset 20, 0 limit 1 to 100, offset up to 1 000 000
/search/articles, /search/posts, /search/people limit, offset 20, 0 limit 1 to 100, offset up to 100 000
/search/suggest limit 5 1 to 10
/articles/:id/citations, /users/:address/citations, /users/:address/lists/:id limit, offset 50, 0 limit 1 to 100
/users/:address/following, /followers limit, offset 100, 0 limit 1 to 1 000
/users/:address/notifications limit 50 1 to 100
/users/:address/feed, /activity limit, before (Unix seconds: items older than it) 50 limit 1 to 100
/notifications after (a notification id), limit 0, 200 limit 1 to 500
/cite ids 1 to 1 000 ids

Search text (q) is cut to 500 characters. Wildcards and regular expressions run on the indexer’s only thread, so they have their own limits: at most 5 per query and 200 characters each; each search may spend 2 seconds on them (then 400, “make it more specific”), and all searches together 20 seconds per minute (then 503, “busy”).

What an uptime monitor reads. 200 while ingestion works:

{ "network": "testnet", "appId": 773893388, "ok": true, "last_ingest_seconds_ago": 2 }

503 when no ingestion poll has succeeded for ARIADNE_STALL_SECONDS (300 by default): the Algorand node is unreachable, a round contradicts the protocol rules, or events are missing (see Ingestion and contract v4). The error says how long and why.

The state of the database:

Field Meaning
genesis_id, genesis_hash the chain the database was built from
schema_version the database schema (18)
watermark the last round ingested
event_seq the event_seq of the last contract event ingested (D-163)
governance the current governance address, from the events
pending_governance the address proposed by governance that has not accepted yet, or null (D-163)
counts rows: events, articles, reviews, comments, fields, content, pinned, pin_failures, identities, orcid_verified, dois, dois_verified, follows, search_articles, search_posts, post_texts, sealed_articles, qualified_reviews, coauthor_checks

The ranked feed.

Parameter Meaning
field articles whose primary or secondary field is this one
type name or number
status name or number; without it, retracted articles are left out
sort score (default) or new
limit, offset paging

Returns { total, articles: [...] }. Each article in a list has these fields:

Field Meaning
article_id, asa_id the article number and its Algorand asset
author the submitting wallet
primary_field, secondary_field field ids (0 = none)
article_type, type the type as a number and as a name
parent_article the amended article, or 0
amendment_by_author for an amendment, whether its submitter is an author of the amended article (false: a third-party note, not the article’s own amendment); null for other types (D-162)
status, status_name, status_before_dispute the status as a number and as a name
version, cid, prev_cid the current version and its CID; prev_cid is null for version 1
created_at, updated_at Unix seconds
vote_total, vote_count the sum of the (damped) vote weights and the number of votes
author_count, invited_count accepted authors; declared co-authors
claimed the author claimed the asset
dispute_round, round_flag_weight the flag round and its weight so far
flag_threshold the weight of flags that disputes the article: always 30 (D-163)
flag_bond the bond a flag on the article deposits now, in microAlgo: 1 000 000, doubled per clearance by governance while the last one is less than 365 days old (at most 16 000 000)
round_started_at the time of the first flag of the current round; null while the round has no flag
round_lapses_at round_started_at + 30 days while the round has flags and the article is not disputed: the round lapses then; null otherwise
disputed_at when the current dispute started; null unless the article is disputed now
retract_after disputed_at + 14 days: governance may retract from then; null unless disputed
dispute_expires_at disputed_at + 60 days: anyone may end the dispute from then; null unless disputed
clearances, cleared_at how many disputes about the article governance cleared (counted up to 4; an expiry does not count), and when the last one was (null when none)
score the ranking score, vote_total / (age_days + 2) ^ 0.8, computed at query time
seal sealed, in_review, changes_requested, suspended or none (see below)
warnings disputed, retracted, and content:<status> when the content is not valid
content validation_status, title, abstract, keywords
Terminal window
curl "https://api.cabdell.press/testnet/articles?field=0x0303&sort=new&limit=5"

One article: { article: {...} } with every list field above, plus:

Field Content
authors[] submitter first, then co-authors by address: address, role (submitter or coauthor), inert (true for an address nobody can sign for, the zero address or the application’s: never a person; D-162), accepted, invited_at, accepted_at, claimed_total, entitled, claimable (null until the co-author confirms), orcid (only a verified iD: id, given_names, family_name, name)
dois[] version (0 = every version), doi, url, status (verified, unlinked, missing, invalid, declared or pending), declared_by, declared_by_submitter, declared_at, checked_at, verified_at, conflicts[] (doi, declared_by, declared_at: other authors’ declarations of another DOI for the version). The DOI shown is the submitter’s, else the latest co-author’s (D-162); since contract v4 only the submitter can declare one (D-163)
duplicate_of[] its CIDs or DOIs that another article used first, which therefore cite that article, not this one (D-162): kind (cid or doi), version, cid, doi, article_id (whose it is); empty when none
citations cited_by, cites, and thread (the article’s Thread Score: percentile, external_citations, cohort, cohort_size; null for amendments and retracted articles)
seal_detail the Peer-reviewed seal in detail (see below)
journals[] the overlay journals that selected it (D-139): owner, list_id, name, added_at, added_by, volume, volume_title, accepted and accepted_at (the submitter accepted the selection; only then is it the article’s journal elsewhere), declined (D-162)
cites_retracted[] the Cabdell articles it cites that were retracted (D-140): article_id, title, retracted_at
versions[] version, cid, prev_cid, ts
reviews[] article_id, review_seq, reviewer, cid, recommendation (1 to 4), created_at, useful_total
comments[] the comment tree: article_id, comment_seq, author, cid, reply_to, root_seq, depth, created_at, vote_total, reply_count, resolved, resolved_at, mentions[], replies[]
votes[] the article’s votes, oldest first (D-163): voter, weight (the damped weight that counted), raw_weight (the voter’s weight before damping), n (the damping divisor: weight = raw_weight ÷ n, rounded down), ts
flags threshold (30, as flag_threshold), bond (the bond in force now, as flag_bond), dispute_round, round_flag_weight, current_round[] (flagger, reason, weight, ts), total_flags
disputes[] dispute_round, outcome (the contract’s code: 1 cleared, 2 retracted, 3 expired), new_status, ts, resolved_by, reasons_cid
content_record cid, available, validation_status, fetched_at, last_checked_at, size_bytes, notice
Terminal window
curl https://api.cabdell.press/testnet/articles/1

One thread: the comment root (required) and every reply under it, ordered by depth, then by creation time. Returns { article_id, root, comments: [...] }.

Parameter Meaning
direction cited_by (default): the Cabdell articles that cite it, newest first, retracted ones left out; cites: those it cites
limit, offset paging

Returns { article_id, direction, total, articles }; each article has the list fields plus citation_kind: amends, note (an “amendment” by someone who is not an author of the article, D-162), link, doi or cid.

What one address has done on one article, so that an interface offers only the actions still possible: voted_article, review_votes[] and comment_votes[] (the numbers voted), reviewed, flagged and reputation (in the article’s primary field). D-163:

Field Meaning
flagged whether the address has flagged in the round a flag would count in now: false once the current round has lapsed, since the next flag opens a new round
reputation_since when the address’s reputation record in the article’s primary field was created (Unix seconds); null without one
can_flag_from from when that record is old enough to flag (30 days after reputation_since); null without a record. The 10 reputation are needed as well

Would a review by this address count toward the article’s seal if it were written now (D-137)? The same checks as the seal, except the text, which is not written yet: favourable and unfavourable give, for each kind of recommendation, {reason, detail, via} (reason null: it counts; reciprocity concerns favourable reviews only); min_words is the length the text needs; openalex_checked says whether every reviewer-author pair has been looked up on OpenAlex (when false, that check happens after the review is published); rule is the rule version. 404 for an article that does not exist.

Terminal window
curl -s https://api.cabdell.press/testnet/articles/1/seal-check/ADDRESS

The routes behind an article’s dispute page and the settlement of bonds (D-151, D-158, D-163). The rules are in Flags, disputes and governance. A round’s outcome is one of:

Outcome Meaning
pending the current round, while it can still become a dispute, or is one
lapsed the round ended without becoming a dispute; the current round shows lapsed once 30 days have passed since its first flag without a dispute
cleared governance cleared the dispute
retracted the article was retracted during the dispute, by governance or by its submitter
expired nobody resolved the dispute within 60 days and someone ended it (not a clearance)

{ article_id, cases: [...], flags: { threshold, bond, rounds: [...] } }: the jury cases of the article’s disputes, newest first, and every round of flags, oldest first. flags.threshold is 30 and flags.bond the bond a flag deposits now (1 000 000 microAlgo, doubled per recent clearance by governance).

Each round of flags.rounds[]:

Field Meaning
round, dispute_round the round’s number
outcome see the table above
weight, total_weight the total weight of the round’s flags
disputed whether the round became a dispute
started_at the time of the round’s first flag
disputed_at when the round became a dispute; null if it did not
resolved_at when the dispute ended; null while it has not
resolved_by who ended it: governance, the submitter (own retraction) or whoever expired it; null while it has not
reasons_cid the CID (CIDv1 text) of governance’s published reasons; null for an expiry, an own retraction, or while unresolved
flags[] each flag: dispute_round, flagger, reason (1 to 4), weight, ts, note (what the flagger wrote, or null), hidden_note (true when the flag has a note that is withheld because the round lapsed; note is then null, and the flag still counted), bond (the bond it deposited), created_at, settled, bond_to (who received the bond or part of it; null until settled), retained (microAlgo the application kept; null until settled), settled_at, settleable (the round is over and the flag is not settled yet: anyone may settle it now)

Each case of cases[] gives the jury: round, attempt, status, scope, the moments opened_at, drawn_at, replace_at (also replace_silent_from) and deadline (also answers_until), the draw (seed_round, seed, the frozen pool eligible with its SHA-256 pool_hash, and pool, the drawn order), seats_total, quorum, age_days, seats[] (each with answer_by and state), the round’s flags, answers and tally (empty and null while the jury sits, answers_hidden true), outcome, fallback, decided_at, resolution, resolved_at and overdue. Since D-163 a case also gives resolved_by and reasons_cid (null until the dispute is resolved) and retract_after, from when governance may retract (14 days after the dispute started). A verdict to retract is overdue only 7 days after the later of the verdict and retract_after. When resolution compares the end of the dispute with the jury’s outcome, an expiry counts as cleared and the submitter’s own retraction as retracted. How juries work is explained in Juries for disputes.

What anyone may settle now on the article: { article_id, settleable: [...] }, each with round, flagger, outcome, bond, bond_to_if_settled (where the bond, or half of it, would go: the flagger after a retraction or a lapse, the submitter after a clearance, the zero address after an expiry), paid_if_settled (what would go to that address) and retained_if_settled (what the application would keep). An interface uses it to offer the settlement of bonds that flaggers lost, which the submitter, or anyone, may send.

Terminal window
curl https://api.cabdell.press/testnet/articles/1/settleable

Every flag of the address, newest first: { flags: [...] }, each with article_id, title, round, weight, reason, bond, created_at, outcome, settled, bond_to, retained, settled_at and settleable. An interface uses it so that a flagger can reclaim the bonds that come back to them.

The seats the address holds in juries that sit now, soonest first: { address, seats: [...] }, each with the article, the round and attempt, answer_by, deadline and the article’s title.

The seal is computed by the indexer from the chain, IPFS, ORCID and OpenAlex (D-131). See The Peer-reviewed seal for the rules.

Where Field Values
every article in a list seal sealed (at least 2 favourable reviews that count, more than the unfavourable ones), changes_requested (at least 2 unfavourable, at least as many as the favourable), in_review (some review counts), suspended (sealed but disputed), none (no review counts, or retracted)
GET /articles/:id seal_detail null when the article has no review; otherwise state, state (also awaiting_orcid: enough reviews, an author without a verified ORCID iD), rule (the rule version, 6), required (2), favourable, unfavourable, sealed_since, reviewed_version (the version current at the latest review that counts), authors_without_orcid[], reviews[]
seal_detail.reviews[] review_seq, reviewer, recommendation, counted, reason (the first rule the review fails: author, orcid, expertise, expertise-authors, expertise-young, expertise-granters, conflict-orcid, conflict-coauthor, conflict-openalex, conflict-institution, conflict-support, text-unread, short, reciprocal, duplicate-orcid; null when it counts), detail (for expertise-* the reputation that counts or the number of people it came from; for conflict-support the author; for duplicate-orcid the review that counted first), via (reputation or openalex: how the reviewer showed expertise)
GET /users/:address seals sealed_articles, qualified_reviews
GET /users/:address, each of reviews[] counted, not_counted_reason whether that review counts toward a seal, and why not; counted is null while it has not been judged
GET /search/articles sealed filter, sealed facet articles that hold the seal

{ user: {...} }, the profile derived from the chain:

Field Content
identity.orcid null, or id, status, declared_at, checked_at, verified_at, retrying, and only while verified: given_names, family_name, name, public (what the record shows to everyone: websites, countries, affiliations; never an e-mail address), citations (OpenAlex counts). D-164: id is null until the iD is verified (anyone can declare anyone’s iD)
follows followers, following
list_count public lists
objections D-164: thread, jury, reputation_display (booleans): what the address objects to (see Privacy and permanence); hidden_by_objection is true when one of them hides a figure
ariadne_citations received, self, cited_articles, thread (score, articles; the person’s Thread Score). With an objection to thread: thread is null and hidden_by_objection true
seals sealed_articles, qualified_reviews
publications[] as submitter and as co-author: article_id, role, accepted, status, status_name, fields, article_type, title, validation_status, cid, published_at, vote_total, seal, entitled, claimed_total, claimable, claimable_today (what a claim would grant now, under the daily cap), cap_left_today (what the cap of its primary field leaves today), claim_allowed (claimable_today above 0)
claimable_total reputation the address can claim today, over all its articles, within the daily cap of each field (D-162)
claimable_total_all the same whatever the daily cap
reviews[], comments[] with the article’s title; reviews also carry counted and not_counted_reason
reputation[] per field: field_id, hex, name, rep, updated_at, cap_day, cap_today, cap_left_today, by_source (D-162: article_votes, useful_reviews, comment_votes, resolutions, the reputation each source gave)
reputation_by_source the same sums over every field
(D-164) with an objection to reputation_display: reputation and reputation_by_source are null, reputation_hidden_by_objection is true, and the timeline leaves out the reputation changes
timeline[] the address’s own events, newest first, at most 200; its votes (voted_article, voted_review, voted_comment) carry amount, the damped weight that counted, with raw_weight and n; its flagged entries carry hidden_note true when their note is withheld because the round lapsed (D-163)
withheld D-164: only when this service withholds the person’s data: the statement of reasons (see What this service withholds); identity is then {orcid: null}
Terminal window
curl https://api.cabdell.press/testnet/users/YOUR_ADDRESS
Parameter Meaning
unread 1 or true: unread only
limit 1 to 100, default 50

Returns { address, unread, notifications: [...] }, newest first; each has id, kind, article_id, comment_seq, actor, ts, read and the article’s title. Kinds: reply, mention, comment_on_my_article, review_on_my_article, comment_resolved, coauthor_invite, followed and the others listed in the indexer’s README. The API is read-only: the web app keeps read marks in the browser. A notification keeps its id for good, even when the indexer rebuilds its tables (D-162).

Contract v4 (D-163) adds these kinds and fields:

Kind To actor data
flag_settled the flagger, and the bond’s recipient (nobody else when the whole bond was kept) '' round, outcome, bond (what went to bond_to), bond_to, retained, flagger
dispute_expired the confirmed authors and the round’s flaggers whoever ended the dispute outcome (expired), to (the status restored), resolved_by, reasons_cid (null)
governance_proposed the current and the proposed governance '' proposed, governance
dispute_resolved (existing) as before governance, or the submitter for their own retraction gains reasons_cid and resolved_by

D-162 (limits): a follow, a mention or a journal’s note from an address with no reputation and no verified ORCID iD, and anything beyond 20 notifications from one sender to one recipient in a day, is folded into one digest entry per day, whose data has day, count, kinds, senders, new_accounts and over_limit. folded=1 lists the folded notifications themselves.

D-164 adds the kind withheld: to the people concerned by something this service withholds (an article’s confirmed authors, a review’s or comment’s author, a list’s or journal’s owner, a flagger, a juror, the person), once per case, unless the case says not to. actor is ''; it links like the record (article_id, review_seq, comment_seq, round, journal); data has kind (what was withheld), id (the case), ground and redress (how to contest it).

The names to show for up to 50 addresses (repeated or comma-separated): { names: {<address>: <name or null>}, hidden: [...] }. A name is the verified ORCID record’s (its published name, else its given and family names); null without a verified iD. D-164: hidden lists the addresses whose names and pictures this service no longer shows (their name is null, and the web app shows neither their NFD name nor their avatar).

GET /users/:address/following and /followers

Section titled “GET /users/:address/following and /followers”

Active on-chain follows, newest first: { address, total, following: [...] } or { address, total, followers: [...] }.

Publications, confirmed co-authorships, reviews and comments of everyone the address follows, newest first: { address, activity: [...] }, each item with kind (published, coauthored, reviewed, commented), actor, article_id, seq, reply_to, ts, title. Page backwards with before.

The same activity for up to 50 addresses given as repeated parameters (address=A&address=B): { activity: [...] }.

The citations the address’s articles received from Cabdell articles, newest citing article first: { address, total, citations: [...] }, each with citing (article_id, title, author, created_at, type), cited (article_id, title), kind and self (the address also wrote the citing article).

The addresses whose declaration of this ORCID iD is verified: { orcid, addresses: [...] }. 400 when the check character is wrong.

Public lists, newest change first: { address, lists: [...] }, each with owner (D-164), list_id, name, about, created_at, updated_at, count and preview (the last three articles added). With article=<id>, each list also says whether it holds that article (contains).

One public list (list: owner, list_id, name, about, created_at, updated_at, count, journal, and for a journal policy and editors[]: address, accepted, invited_at, accepted_at) and its articles, last added first, each with the list fields, added_at, added_by (who selected it) and volume. A journal’s list also gives volume (the open one) and volumes[] (open one first: volume, title, opened_at, closed_at, count, editors, the board kept when it closed); volume=<n> returns that volume’s articles only (D-141). 404 when the address has no such list.

Every overlay journal (D-139), the most articles first: { journals: [...] } with owner, list_id, name, about, policy, created_at, updated_at, count, editors (accepted editors, the founder included) and volumes.

The journals the address founded, edits or is invited to: { address, journals: [...] } with owner, list_id, name and role (founder, editor or invited); with article=<id>, contains says whether each holds it.

Journal notes use the list prefix (ariadne/lists/<appId>:) with these operations, besides those of lists: the founder’s {"op":"journal","list":"<id>","policy":"…"} (or "off":true), {"op":"invite"|"dismiss","list":"<id>", "editors":[…]} (at most 10 per operation, 30 editors in all); an invited editor’s {"op":"editor","journal":"<OWNER>/<id>", "accept":true|false}; the founder’s or an accepted editor’s {"op":"select"|"unselect","journal":"<OWNER>/<id>", "articles":[…]}; the founder’s {"op":"volume","list":"<id>","title":"…"} opens the next volume (closing the open one, which must not be empty) and {"op":"volume","list":"<id>","title":"…","current":true} renames the open one (D-141).

The same notes carry an address’s objection to profiling (D-164, GDPR art. 21), for itself only: {"op":"objection","to":["thread","jury","reputation_display"],"on":true} (one to three of these items; "on":false withdraws the objection; for each item the latest note stands). thread hides the address’s Thread Score, reputation_display its reputation figures (profile and people search), and jury keeps the person (every address of their verified iD) out of every jury pool and draw from then on. A note with anything else changes nothing. The note is public, like every note.

What a bibliography needs of each article: ?ids=1,2,3 (1 to 1 000 ids) or ?owner=<address>&list=<id> (a whole public list). Returns { articles: [...] } in the order asked, unknown ids left out; each with article_id, title, type, status_name, version, published, cid, authors[] (address, orcid) and dois[] (version, doi, status).

Full-text search over articles, reviews and comments, and people (D-120, D-121). See Search for the query syntax as readers use it.

Query syntax: words (all required), "a phrase", -word, OR, prefix*, the parts title:, abstract:, keyword:, body:, author: (a name or an address) and field:, and exact lookups doi: (or a bare DOI), cid: and #12. Wildcards inside a word (wom?n, *ology) and regular expressions between slashes (/memor(y|ies)/, title:/^sleep/, -/x/) are tested on the texts without accents, case ignored. Highlighted words come between the characters U+0002 and U+0003, never as HTML.

Parameter Meaning
q the query
field fields (primary or secondary, unless primary_only=true)
primary_only match field against the primary field only
area areas (the high byte of a field id, 1 to 6), matched against the primary or secondary field
type types
status statuses; retracted articles are left out unless chosen; all for every status
author an address (submitter or accepted co-author)
submitter_only author must be the submitter
reviewer, commenter an address that reviewed or commented on the article
followed_by articles by people this address follows
orcid an author’s verified ORCID iD
published_from, published_to publication date (YYYY, YYYY-MM or YYYY-MM-DD, UTC; _to inclusive)
updated_from, updated_to the article’s updated_at, same format: the last call that changed its on-chain record (a version, a status change, an article vote, a review, a comment, a flag…)
min_votes, min_voters minimum vote weight, minimum number of votes
min_reviews, max_reviews number of reviews
recommendation recommendations received (names or 1 to 4)
min_comments number of comments
has_doi, doi_verified a DOI that is verified, cannot be checked (declared) or is not checked yet (never one whose record does not point back); a verified DOI
orcid_verified at least one author with a verified ORCID iD
sealed holds the Peer-reviewed seal
language, license from the front-matter
valid_only content checked as valid
revised has more than one version
amends amendments of this article number
has_amendments has been amended
keyword keywords
sort relevance (default with a query), score (default without), new, old, votes, reviews, comments, updated, cited (most cited on Cabdell)
limit, offset paging

Returns query (how the query was read: terms, doi, cid, article_id, authors, notes, sort), total, articles (the list fields plus review_count, comment_count, cited_by, authors, doi and match, the highlighted passages) and facets. Each facet counts its options under every other filter in use: fields, areas, types, statuses, years, languages, licenses, recommendations, has_doi, doi_verified, orcid_verified, revised, sealed, unreviewed, reviewed, valid, has_amendments.

Terminal window
curl "https://api.cabdell.press/testnet/search/articles?q=sleep&field=0x0303&sealed=true&sort=new"

Reviews and comments by their text.

Parameter Meaning
q the query
kind review, comment
recommendation for reviews (names or 1 to 4)
field the article’s primary or secondary field
author an address
article an article number
from, to dates, same format as above
sort relevance (default with a query), new (default without), old, votes

Returns query, total, posts (kind, article_id, seq, author, author_name, reply_to_review, recommendation, created_at, votes, reply_to, article_title, article_status, primary_field, text_available, excerpt) and facets.

Parameter Meaning
q a verified ORCID name, an ORCID iD or the start of an address
role author, reviewer, commenter
field reputation in this field
orcid_verified only people with a verified ORCID iD
address specific addresses
sort relevance (default with a query), reputation (default without), publications, reviews, recent

Returns { total, people, notes }. D-164: a person who objects to the display of their reputation has reputation and field_reputation null and hidden_by_objection true, and sorts as having none.

Suggestions while typing: { articles, keywords, fields, people } for q, at most limit (1 to 10, default 5) of each.

The registered fields, { fields: [...] }, each with field_id, name, hex and articles (articles that are not retracted, under this field as primary or secondary). See Fields.

Cabdell stops showing something on its own service only on these grounds (D-164): order (a court or an authority), notice (a substantiated notice of manifestly illegal content), terms (spam, malware, phishing), data_protection (a request about one’s own data), copyright, csam (child sexual abuse material), terrorist, other. See Privacy and permanence. The record on the blockchain is unchanged; the API leaves out what is withheld and gives, in its place, a statement of reasons:

{ "id": "W-7", "ground": "notice", "reason": "notice", "basis": "…the facts and the rule, in a sentence…",
"date": "2026-10-08", "scope": "this service",
"redress": "To contest this decision, write to the operator (…) quoting W-7, in English or Spanish. You may also take it to the courts.",
"decided_at": 1791417600, "published_at": 1791417600 }

reason repeats ground (older clients read it); decided_at and published_at are Unix seconds (00:00 UTC of the decision and of its publication in the transparency report). Child sexual abuse material is shown with the ground other and a neutral basis, so that a record’s page never points to such material.

What is withheld What the API leaves out Where the statement of reasons is
an article its title, abstract, keywords, snippets and every CID of its versions (wherever the article appears: feed, search, lists, profiles, notifications) withheld on the article
a review or a comment its text, excerpt and CID withheld on the review or comment
a list or a journal its name, about, policy (and its volumes’ titles) withheld on the list or journal (also inside a notification’s journal)
a journal volume its title withheld on the volume; volume_withheld beside a volume_title
a flag’s note note note_withheld on the flag (and on the flagger’s flagged timeline entry)
a juror’s reasons reasons reasons_withheld on the answer
a person (an address) their names and ORCID data everywhere (identity: {orcid: null}; orcid, name null in authors, seats, pools, people) withheld on their profile; /names lists them in hidden
a raw CID that CID wherever it would appear (none)

Search never finds what is withheld by its text, and the indexer purges its own copies of the texts.

The transparency report: { entries: [...], counts: [...] }.

  • entries: the cases published by now (their published_at has come), newest first, each with id, kind (article, review, comment, list, journal, volume, flag_note, verdict, address, cid), app (the application, or null for the current one), the record (article, seq, owner, list, volume, round, flagger, juror; null when they do not apply), published and the statement of reasons. Never a CID or a person’s address. Cases of the grounds csam, terrorist and data_protection are not listed one by one.
  • counts: every published case counted by month (YYYY-MM of the decision), ground and kind: { month, ground, kind, n }, newest month first.
Terminal window
curl https://api.cabdell.press/testnet/withheld

Every address’s notifications created after the id after, oldest first, with latest (the highest id so far). The web server’s Web Push sender polls this route, one request per network. Notifications are public data already.

Terminal window
curl "https://api.cabdell.press/testnet/notifications?after=0&limit=10"

The indexer serves contract v4 only: at start it compares the application’s program with the one it was built for and refuses any other (D-162), so an indexer of this version cannot read an application of an earlier contract. Every contract event carries event_seq, a number that the contract gives its events from 1 without gaps; the indexer stores it. If the next event it reads does not follow the last one it stored, events were missed (for example, a public endpoint answered from an Algorand indexer that was behind): the poll fails with “missing events” and the watermark does not move, so the next poll reads the same rounds again. /status gives the last event_seq ingested. See Run an indexer.