DevelopersUsing the API
API reference
ChassidusHub API 1.0.0: 205 routes in 25 groups, read from the API's own OpenAPI document.
https://api.chassidushub.orgFor what needs a signed-in person, paste a personal token. It is sent only to the API, and forgotten when you leave the page.
About#
This API, the catalog in numbers
- GET
/Redirects to /v1 - GET
/v1About this API: its version, the latest commit, where the docs are - GET
/openapi.jsonThis document - GET
/v1/statsHow many items of each type, and the latest commit - GET
/v1/communityThe community page in numbers: the latest merges, reports and suggestions waiting, people, gaps - GET
/v1/statusWhether ChassidusHub is up: the last checks of the site, the API, the MCP server, the database, its daily query allowance, the Workers' load and the scheduled jobs, with 90 days of them and the latest incidents - GET
/v1/healthThe health of the catalog: coverage per year and set, unchecked pages, unsynced recordings, dead links, the oldest open suggestions
Redirects to /v1#
GETGET /
curl 'https://api.chassidushub.org/'Try it
About this API: its version, the latest commit, where the docs are#
GETGET /v1
curl 'https://api.chassidushub.org/v1'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.about();Try it
This document#
GETGET /openapi.json
curl 'https://api.chassidushub.org/openapi.json'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.openapi();Try it
How many items of each type, and the latest commit#
GETGET /v1/stats
curl 'https://api.chassidushub.org/v1/stats'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.stats();Try it
The community page in numbers: the latest merges, reports and suggestions waiting, people, gaps#
GETGET /v1/community
Parameters
limitintegerqueryHow many (at most 50)
curl 'https://api.chassidushub.org/v1/community'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.community();Try it
Whether ChassidusHub is up: the last checks of the site, the API, the MCP server, the database, its daily query allowance, the Workers' load and the scheduled jobs, with 90 days of them and the latest incidents#
GETGET /v1/status
Checked every five minutes; read from storage, never from the database, so it answers when the database does not. `report` is null until the first check. When `report.checkedAt` is much older than `now`, the checks have stopped running.
curl 'https://api.chassidushub.org/v1/status'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.status();Try it
The health of the catalog: coverage per year and set, unchecked pages, unsynced recordings, dead links, the oldest open suggestions#
GETGET /v1/health
Parameters
limitintegerqueryHow many (at most 500)
curl 'https://api.chassidushub.org/v1/health'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.health();Try it
Items#
Every sefer, sicha, letter, farbrengen, printing, scan and recording: by id, path, type, set and date, with history
- GET
/v1/typesEvery kind of item and its JSON Schema - GET
/v1/entitiesItems on main, by type and set, in path order, a page at a time - GET
/v1/entities/batchSeveral items at once, in the order asked (missing ones left out) - GET
/v1/entities/{id}One item, on main or as of a commit - GET
/v1/entities/{id}/childrenAn item's children in their own order (a work's units, a text's paragraphs), a page at a time - GET
/v1/entities/{id}/linked/countsWhat points at an item, by type and field, with how many of each - GET
/v1/entities/batch/linkedOne group of what points at each of several items, a few of each in the group's order: what a list needs of every row in one request (a sefer's sichos' texts, a farbrengen's sichos' words) - GET
/v1/entities/{id}/linkedOne group of what points at an item, in its own order, a page at a time, with the total - GET
/v1/entities/{id}/shaarA sefer's shaar file, the README of a sefer, in its fixed form (docs/shaar.md) - GET
/v1/entities/{id}/historyEvery merged change to an item, newest first: who, when, and what changed field by field - GET
/v1/entities/{id}/backlinksItems that point at this one - GET
/v1/entities/{id}/relationsAn item's links both ways: cites, printed in, based on, cited by - GET
/v1/revisions/{rev}One stored version of an item - GET
/v1/resolveThe item at a readable path (an old path answers with where it moved) - GET
/v1/eventsFarbrengens and other events by Hebrew date, each with how many recordings it has - GET
/v1/refcountsHow many items point at each item through a field (field=work&type=unit: each work's units) - GET
/v1/sitemapEvery sitemap there is: each kind of item with a page of its own, in pages of pageSize items (id order), with when each page last changed - GET
/v1/sitemap/{type}/{page}One sitemap's items: their ids, paths and when each last changed - GET
/v1/works/{id}/outlineA work's volumes (its top-level parts), with how many units each holds - GET
/v1/works/{id}/parts/{part}The units of one volume of a work - GET
/v1/units/{id}/neighboursThe units just before and after a unit in its work's order, across volumes: a sicha's previous and next - GET
/v1/commitsEvery merge to main after a given one, in order, with what each changed: the way to follow the catalog without webhooks
Every kind of item and its JSON Schema#
GETGET /v1/types
curl 'https://api.chassidushub.org/v1/types'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.types();Try it
Items on main, by type and set, in path order, a page at a time#
GETGET /v1/entities
Parameters
typestringqueryOne of set, author, work, unit, event, publication, scan, contents-map, text-layer, text-page, text, segment, recording, alignment, alignment-span, relation, person, place, topic, source, schema
setstringqueryOnly items in this set
shelfbooleanqueryWhat a shelf lists: leaves out the additions to a sefer (a work's addition.to), which are listed on that sefer's page
officialbooleanquerytrue: only the official sefarim the tree is built of (no additions); false: only additions
additions-ofstringqueryOnly the additions to this sefer
afterstringqueryDeprecated: the same as cursor
limitintegerqueryHow many (at most 500)
cursorstringqueryThe `next` of the page before
curl 'https://api.chassidushub.org/v1/entities'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
for await (const item of rh.all('listItems', {})) {
console.log(item);
}Try it
Several items at once, in the order asked (missing ones left out)#
GETGET /v1/entities/batch
Parameters
idsstringqueryrequiredThe ids
curl 'https://api.chassidushub.org/v1/entities/batch?ids=%3Cids%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getItems({
ids: "<ids>"
});Try it
One item, on main or as of a commit#
GETGET /v1/entities/{id}
Words whose rights forbid copies are left out, and `withheld` says why.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
atintegerqueryA commit's seq: the item as it was then
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getItem({
id: "rh-7k2m9q4d"
});Try it
An item's children in their own order (a work's units, a text's paragraphs), a page at a time#
GETGET /v1/entities/{id}/children
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
fieldstringqueryrequiredThe children's field that points at this item (work, text, event…)
typestringqueryrequiredThe children's type (unit, segment, recording…)
afterstringqueryDeprecated: the same as cursor
limitintegerqueryHow many (at most 1000)
cursorstringqueryThe `next` of the page before
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/children?field=%3Cfield%3E&type=%3Ctype%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
for await (const item of rh.all('listChildren', {
id: "rh-7k2m9q4d",
field: "<field>",
type: "<type>"
})) {
console.log(item);
}Try it
What points at an item, by type and field, with how many of each#
GETGET /v1/entities/{id}/linked/counts
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/linked/counts'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.linkedCounts({
id: "rh-7k2m9q4d"
});Try it
One group of what points at each of several items, a few of each in the group's order: what a list needs of every row in one request (a sefer's sichos' texts, a farbrengen's sichos' words)#
GETGET /v1/entities/batch/linked
Parameters
idsstringqueryrequiredThe items
fieldstringqueryrequiredThe field that points at them (unit, text, publication…)
typestringqueryOnly items of this type
limitintegerqueryHow many (at most 500)
curl 'https://api.chassidushub.org/v1/entities/batch/linked?ids=%3Cids%3E&field=%3Cfield%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.linkedOfEach({
ids: "<ids>",
field: "<field>"
});Try it
One group of what points at an item, in its own order, a page at a time, with the total#
GETGET /v1/entities/{id}/linked
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
fieldstringqueryrequiredThe field that points here (work, event, sets…; addition.to for the additions to a sefer)
typestringqueryOnly items of this type
afterstringqueryDeprecated: the same as cursor
limitintegerqueryHow many (at most 500)
cursorstringqueryThe `next` of the page before
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/linked?field=%3Cfield%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
for await (const item of rh.all('listLinked', {
id: "rh-7k2m9q4d",
field: "<field>"
})) {
console.log(item);
}Try it
A sefer's shaar file, the README of a sefer, in its fixed form (docs/shaar.md)#
GETGET /v1/entities/{id}/shaar
For a sefer no person has written one for, the one the catalog makes from its data, with `machine` true. `?format=text` gives the file itself.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
formatjson | textquerytext: the file itself, as text/markdown
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/shaar'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getShaar({
id: "rh-7k2m9q4d"
});Try it
Every merged change to an item, newest first: who, when, and what changed field by field#
GETGET /v1/entities/{id}/history
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/history'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.itemHistory({
id: "rh-7k2m9q4d"
});Try it
Items that point at this one#
GETGET /v1/entities/{id}/backlinks
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
fieldstringqueryOnly links in this field
typestringqueryOnly items of this type
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/backlinks'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.itemBacklinks({
id: "rh-7k2m9q4d"
});Try it
An item's links both ways: cites, printed in, based on, cited by#
GETGET /v1/entities/{id}/relations
Each is `machine: true` while a machine found it and no person has checked it.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/relations'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.itemRelations({
id: "rh-7k2m9q4d"
});Try it
One stored version of an item#
GETGET /v1/revisions/{rev}
Parameters
revintegerpathrequiredA revision id
curl 'https://api.chassidushub.org/v1/revisions/1'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getRevision({
rev: 1
});Try it
The item at a readable path (an old path answers with where it moved)#
GETGET /v1/resolve
Parameters
pathstringqueryrequiredA path such as /likkutei-sichos/12/3
curl 'https://api.chassidushub.org/v1/resolve?path=%2Fevents%2F5742-05-10'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.resolvePath({
path: "/events/5742-05-10"
});Try it
Farbrengens and other events by Hebrew date, each with how many recordings it has#
GETGET /v1/events
Parameters
withinstringqueryA year (5742) or a month (5742-05)
daystringqueryA day of any year (05-10), or several, comma separated
datesstringqueryExact dates, comma separated (5742-05-10,5743-05-10)
missingrecordings | textsqueryOnly those without
brief1queryWith 1: each event's facts with each link's kind alone, not its label and pages, for a calendar's rows (well under half the bytes)
limitintegerqueryHow many (at most 2000)
curl 'https://api.chassidushub.org/v1/events'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.listEvents();Try it
How many items point at each item through a field (field=work&type=unit: each work's units)#
GETGET /v1/refcounts
Parameters
fieldstringqueryrequiredThe field
typestringqueryOnly items of this type
curl 'https://api.chassidushub.org/v1/refcounts?field=%3Cfield%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.refCounts({
field: "<field>"
});Try it
Every sitemap there is: each kind of item with a page of its own, in pages of pageSize items (id order), with when each page last changed#
GETGET /v1/sitemap
What the site's /sitemap.xml is made from. Kinds: set, author, person, work, unit, event, publication, recording.
curl 'https://api.chassidushub.org/v1/sitemap'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.sitemaps();Try it
One sitemap's items: their ids, paths and when each last changed#
GETGET /v1/sitemap/{type}/{page}
Parameters
typeset | author | person | work | unit | event | publication | recordingpathrequiredA kind of item with a page of its own
pageintegerpathrequiredFrom 1
curl 'https://api.chassidushub.org/v1/sitemap/set/1'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.sitemapPage({
type: "set",
page: 1
});Try it
A work's volumes (its top-level parts), with how many units each holds#
GETGET /v1/works/{id}/outline
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/works/rh-7k2m9q4d/outline'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.workOutline({
id: "rh-7k2m9q4d"
});Try it
The units of one volume of a work#
GETGET /v1/works/{id}/parts/{part}
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
partstringpathrequiredThe volume, as the outline names it
limitintegerqueryHow many (at most 1000)
curl 'https://api.chassidushub.org/v1/works/rh-7k2m9q4d/parts/<part>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.workPart({
id: "rh-7k2m9q4d",
part: "<part>"
});Try it
The units just before and after a unit in its work's order, across volumes: a sicha's previous and next#
GETGET /v1/units/{id}/neighbours
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/units/rh-7k2m9q4d/neighbours'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.unitNeighbours({
id: "rh-7k2m9q4d"
});Try it
Every merge to main after a given one, in order, with what each changed: the way to follow the catalog without webhooks#
GETGET /v1/commits
Parameters
sinceintegerqueryStart after this commit's seq (0: from the start)
limitintegerqueryHow many (at most 100)
changesintegerqueryCarry only so many of each commit's changes (an import's has thousands); `changed` and `types` still count them all
cursorstringqueryThe `next` of the page before
curl 'https://api.chassidushub.org/v1/commits'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
for await (const item of rh.all('listCommits', {})) {
console.log(item);
}Try it
Search#
By names and dates, inside the words, and by meaning
- GET
/v1/dates/parseRead a Hebrew date as people write it - GET
/v1/searchSearch names, text and dates, in Hebrew or English - GET
/v1/mafteachA sefer's whole subject index on one page, gathered from its volumes' index pages: every topic once, each volume's places under it with their context and links (the sicha's PDF at that page, the sicha's page here); one first letter's topics, or those a search finds - GET
/v1/search/momentsWhere the words are: lines on scans' pages (open at the line) and paragraphs of texts and transcripts (open at the moment heard) - GET
/v1/search/similarSearch by meaning (embeddings); every result is the machine's guess
curl 'https://api.chassidushub.org/v1/dates/parse?q=%D7%99%D7%95%22%D7%93%20%D7%A9%D7%91%D7%98%20%D7%AA%D7%A9%D7%9B%22%D7%91'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.parseDate({
q: "יו\"ד שבט תשכ\"ב"
});Try it
Search names, text and dates, in Hebrew or English#
GETGET /v1/search
Ranked by relevance, not paged: ask for more with limit. A query that names a Hebrew date also answers with the date.
Parameters
qstringqueryrequiredThe query
typestringqueryOnly this type
workstringqueryOnly items of this sefer (its printings, its sichos)
limitintegerqueryHow many (at most 100)
curl 'https://api.chassidushub.org/v1/search?q=%D7%99%D7%95%22%D7%93%20%D7%A9%D7%91%D7%98'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.search({
q: "יו\"ד שבט"
});Try it
A sefer's whole subject index on one page, gathered from its volumes' index pages: every topic once, each volume's places under it with their context and links (the sicha's PDF at that page, the sicha's page here); one first letter's topics, or those a search finds#
GETGET /v1/mafteach
Built from the index pages as they are now, and kept until one changes. Places a machine read and no person checked are marked machine, volume by volume.
Parameters
indexstringqueryrequiredThe index: a work whose units are its volumes' index pages (an id, or its path, like /likkutei-sichos-mafteach-inyanim)
seferstringqueryThe sefer it indexes (an id or path), for the links to its sichos
letterstringqueryOne first letter's topics (the first letter when neither this nor q is given)
qstringqueryTopics whose name, context or sicha holds these words
limitintegerqueryHow many (at most 200)
placesintegerqueryStop the page sooner, at about this many places (never at no topic)
offsetintegerqueryTopics to skip: the `next` of the page before
curl 'https://api.chassidushub.org/v1/mafteach?index=%3Cindex%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.mafteach({
index: "<index>"
});Try it
Where the words are: lines on scans' pages (open at the line) and paragraphs of texts and transcripts (open at the moment heard)#
GETGET /v1/search/moments
Parameters
qstringqueryrequiredThe words
limitintegerqueryHow many (at most 100)
curl 'https://api.chassidushub.org/v1/search/moments?q=%D7%99%D7%95%22%D7%93%20%D7%A9%D7%91%D7%98'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.searchMoments({
q: "יו\"ד שבט"
});Try it
Search by meaning (embeddings); every result is the machine's guess#
GETGET /v1/search/similar
`available` is false until it is set up on the server.
Parameters
qstringqueryrequiredA question or an idea, in Hebrew, Yiddish or English
typesstringquerySome of unit, event, segment, text-page, work, comma separated
limitintegerqueryHow many (at most 50)
curl 'https://api.chassidushub.org/v1/search/similar?q=%D7%99%D7%95%22%D7%93%20%D7%A9%D7%91%D7%98'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.searchSimilar({
q: "יו\"ד שבט"
});Try it
Texts#
Scans' texts line by line, printings compared, translations
- GET
/v1/texts/batch/progressHow many paragraphs each of several texts has, how many of them a person checked, and how many a machine made that nobody checked yet - GET
/v1/dailyA day's learning: Chitas (Tanya, the day's portion, each chapter it touches cut to it; Chumash with Rashi; Tehillim), Hayom Yom, and the Rambam's three tracks - GET
/v1/shiurimThe shiurim's words, each page cut to what is learned: a day's (Chumash by aliyah with Rashi, Tehillim, Tanya, the Rambam's three tracks), or any by Sefaria's references - GET
/v1/scans/{id}/textA page of a scan's text: the community page, else the seed layer's; each line with its proofread level - GET
/v1/scans/{id}/progressHow far each page of a scan is proofread (0, 1 or 2) - POST
/v1/scans/{id}/text/fixFix one line of a scan's text (a suggestion) - POST
/v1/scans/{id}/text/confirmThis page is right: raise it a proofreading level, with any fixes (a suggestion) - POST
/v1/scans/{id}/ocrUpload your own OCR of a scan (hOCR, ALTO, or plain text with form feeds between pages) as a new layer - POST
/v1/scans/{id}/text/seedKeepers: seed the community text from this OCR layer (checked lines are kept) - GET
/v1/units/{id}/printingsThe printings of a unit whose text the catalog has, to compare - GET
/v1/compareCompare two printings word by word (Hebrew-aware) - POST
/v1/units/{id}/translationsSuggest a translation of a unit, as its own text - POST
/v1/translations/fixSuggest a fix to one paragraph of a translation - POST
/v1/hanachos/textA hanacha's words for a farbrengen or sicha (or a new farbrengen), a paragraph to a segment - GET
/v1/texts/{sha256}A text of a sefer as its source gave it (one chapter or letter, an HTML article)
How many paragraphs each of several texts has, how many of them a person checked, and how many a machine made that nobody checked yet#
GETGET /v1/texts/batch/progress
Parameters
idsstringqueryrequiredThe texts
curl 'https://api.chassidushub.org/v1/texts/batch/progress?ids=%3Cids%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.textsProgress({
ids: "<ids>"
});Try it
A day's learning: Chitas (Tanya, the day's portion, each chapter it touches cut to it; Chumash with Rashi; Tehillim), Hayom Yom, and the Rambam's three tracks#
GETGET /v1/daily
The day is the civil day it is learned on. Tanya follows the yearly cycle from 19 Kislev (Sefaria's Tanya Yomi); Hayom Yom gives both Adars' entries in a plain year's Adar. Each Tanya chapter says where the portion starts (`from`) and the first segment after it (`to`, null to its end). Chumash (the week's parsha, an aliyah a day, outside the Land of Israel), Tehillim (the monthly cycle, with Elul's and the ten days' three more) and the Rambam (three chapters, one chapter, Sefer HaMitzvos) are named in Hebrew and by Sefaria's references.
Parameters
datestringqueryrequiredThe civil day
curl 'https://api.chassidushub.org/v1/daily?date=2026-09-30'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.dailyLearning({
date: "2026-09-30"
});Try it
The shiurim's words, each page cut to what is learned: a day's (Chumash by aliyah with Rashi, Tehillim, Tanya, the Rambam's three tracks), or any by Sefaria's references#
GETGET /v1/shiurim
Give `date` for a day's shiurim, or `ref` (up to ten, with `rashi=1` for a Chumash reference's Rashi too) for any. Each section names what it is (`chumash`, `tehillim`, `tanya`, `three`, `one`, `mitzvos`, or `passage`) and holds its pages, each in its Hebrew only, cut to the stretch learned (`from`, and `to` the first segment after it, null to its end); a Rashi page is marked `rashi`. A reference the catalog has no page for is left out.
Parameters
datestringqueryThe civil day
refstringqueryA Sefaria reference; repeat for more
rashistringqueryWith a Chumash reference, its Rashi too
curl 'https://api.chassidushub.org/v1/shiurim'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.shiurim();Try it
A page of a scan's text: the community page, else the seed layer's; each line with its proofread level#
GETGET /v1/scans/{id}/text
Lines nobody has checked are machine reading (`checked: false`). Withheld when the scan may not be served.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
pageintegerqueryThe page
curl 'https://api.chassidushub.org/v1/scans/rh-7k2m9q4d/text'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.scanText({
id: "rh-7k2m9q4d"
});Try it
How far each page of a scan is proofread (0, 1 or 2)#
GETGET /v1/scans/{id}/progress
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/scans/rh-7k2m9q4d/progress'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.scanProgress({
id: "rh-7k2m9q4d"
});Try it
Fix one line of a scan's text (a suggestion)#
POSTPOST /v1/scans/{id}/text/fix
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"page": {
"type": "integer"
},
"line": {
"type": "string",
"description": "The line's id"
},
"text": {
"type": "string"
}
},
"required": [
"page",
"line",
"text"
]
}curl -X POST 'https://api.chassidushub.org/v1/scans/rh-7k2m9q4d/text/fix' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"page":1,"line":"<line>","text":"<text>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.fixScanLine({
id: "rh-7k2m9q4d",
body: {
page: 1,
line: "<line>",
text: "<text>"
}
});Try it
This page is right: raise it a proofreading level, with any fixes (a suggestion)#
POSTPOST /v1/scans/{id}/text/confirm
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"page": {
"type": "integer"
},
"fixes": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"description": "Line id to its right text"
}
},
"required": [
"page"
]
}curl -X POST 'https://api.chassidushub.org/v1/scans/rh-7k2m9q4d/text/confirm' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"page":1}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.confirmScanPage({
id: "rh-7k2m9q4d",
body: {
page: 1
}
});Try it
Upload your own OCR of a scan (hOCR, ALTO, or plain text with form feeds between pages) as a new layer#
POSTPOST /v1/scans/{id}/ocr
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"content": {
"type": "string"
},
"format": {
"enum": [
"hocr",
"alto",
"text"
]
},
"engine": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"version": {
"type": "string"
}
},
"required": [
"name",
"version"
]
},
"firstPage": {
"type": "integer",
"minimum": 1
},
"language": {
"type": "string"
}
},
"required": [
"content",
"engine"
]
}curl -X POST 'https://api.chassidushub.org/v1/scans/rh-7k2m9q4d/ocr' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"content":"<content>","engine":{"name":"<name>","version":"<version>"}}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.uploadOcr({
id: "rh-7k2m9q4d",
body: {
content: "<content>",
engine: {
name: "<name>",
version: "<version>"
}
}
});Try it
Keepers: seed the community text from this OCR layer (checked lines are kept)#
POSTPOST /v1/scans/{id}/text/seed
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"layer": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
}
},
"required": [
"layer"
]
}curl -X POST 'https://api.chassidushub.org/v1/scans/rh-7k2m9q4d/text/seed' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"layer":"rh-7k2m9q4d"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.seedScanText({
id: "rh-7k2m9q4d",
body: {
layer: "rh-7k2m9q4d"
}
});Try it
The printings of a unit whose text the catalog has, to compare#
GETGET /v1/units/{id}/printings
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/units/rh-7k2m9q4d/printings'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.unitPrintings({
id: "rh-7k2m9q4d"
});Try it
Compare two printings word by word (Hebrew-aware)#
GETGET /v1/compare
Parameters
astringqueryrequiredtext:<id> or scan:<id>:<from>-<to>
bstringqueryrequiredThe other printing
curl 'https://api.chassidushub.org/v1/compare?a=%3Ca%3E&b=%3Cb%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.comparePrintings({
a: "<a>",
b: "<b>"
});Try it
Suggest a translation of a unit, as its own text#
POSTPOST /v1/units/{id}/translations
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"language": {
"type": "string"
},
"credit": {
"type": "string"
},
"licence": {
"enum": [
"public-domain",
"cc0",
"cc-by",
"cc-by-nc"
]
},
"translationOf": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"content": {
"type": "string",
"description": "A blank line between paragraphs"
},
"machine": {
"type": "string",
"description": "The tool, when a machine translated it"
}
},
"required": [
"language",
"credit",
"content"
]
}curl -X POST 'https://api.chassidushub.org/v1/units/rh-7k2m9q4d/translations' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"language":"<language>","credit":"<credit>","content":"<content>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.addTranslation({
id: "rh-7k2m9q4d",
body: {
language: "<language>",
credit: "<credit>",
content: "<content>"
}
});Try it
Suggest a fix to one paragraph of a translation#
POSTPOST /v1/translations/fix
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"segment": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"content": {
"type": "string"
}
},
"required": [
"segment",
"content"
]
}curl -X POST 'https://api.chassidushub.org/v1/translations/fix' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"segment":"rh-7k2m9q4d","content":"<content>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.fixTranslation({
body: {
segment: "rh-7k2m9q4d",
content: "<content>"
}
});Try it
A hanacha's words for a farbrengen or sicha (or a new farbrengen), a paragraph to a segment#
POSTPOST /v1/hanachos/text
Words of unsure rights are kept and not shown until a steward decides. Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"for": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"eventTitle": {
"type": "string",
"description": "For a farbrengen the catalog lacks: its name"
},
"eventDate": {
"type": "string",
"description": "With eventTitle: its date key"
},
"content": {
"type": "string",
"description": "A blank line between paragraphs"
},
"rights": {
"enum": [
"mine",
"public-domain",
"free",
"unsure"
]
},
"language": {
"type": "string"
},
"credit": {
"type": "string"
}
},
"required": [
"content",
"rights"
]
}curl -X POST 'https://api.chassidushub.org/v1/hanachos/text' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"content":"<content>","rights":"mine"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.addHanachaText({
body: {
content: "<content>",
rights: "mine"
}
});Try it
A text of a sefer as its source gave it (one chapter or letter, an HTML article)#
GETGET /v1/texts/{sha256}
Parameters
sha256stringpathrequiredA file, named by its sha256
curl 'https://api.chassidushub.org/v1/texts/<sha256>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getSourceText({
sha256: "<sha256>"
});Try it
Media#
Transcripts and their sync
- GET
/v1/transcriptsEvery recording that has a transcript, the most checked first, then the longest - GET
/v1/transcripts/fixesEvery transcript fix waiting for approval, to go through together: each paragraph on the site and as the fix would make it, where it is heard, who sent it, and whether you may approve it - POST
/v1/transcripts/fixes/decideKeep some transcript fixes and remove others in one go: kept ones are approved; removed ones are withdrawn if they are yours, else sent back with the note - GET
/v1/recordings/{id}/transcriptA recording's transcript, with its sync by paragraph and word - GET
/v1/recordings/{id}/transcript/historyEverything that happened to a recording's transcript, newest first - POST
/v1/recordings/{id}/transcript/fixFix the words of one paragraph of a transcript (a suggestion) - POST
/v1/recordings/{id}/sync/anchorThe Rebbe is saying this line now: set a paragraph (or word) at atMs, lock it, move what follows - POST
/v1/recordings/{id}/sync/confirmThe sync is right: mark every paragraph checked - GET
/v1/recordings/batch/hanachaSeveral recordings' synced hanachos at once (a farbrengen's parts), by recording; those with none are left out - GET
/v1/recordings/{id}/hanachaThe hanacha synced to this recording, paragraph by paragraph
Every recording that has a transcript, the most checked first, then the longest#
GETGET /v1/transcripts
Parameters
limitintegerqueryHow many (at most 1000)
curl 'https://api.chassidushub.org/v1/transcripts'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.transcribedRecordings();Try it
Every transcript fix waiting for approval, to go through together: each paragraph on the site and as the fix would make it, where it is heard, who sent it, and whether you may approve it#
GETGET /v1/transcripts/fixes
No account needed; signed in, a little more.
Parameters
limitintegerqueryHow many (at most 200)
curl 'https://api.chassidushub.org/v1/transcripts/fixes'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.transcriptFixes();Try it
Keep some transcript fixes and remove others in one go: kept ones are approved; removed ones are withdrawn if they are yours, else sent back with the note#
POSTPOST /v1/transcripts/fixes/decide
Signed in: an API token with the write scope, or the site's session.
Body application/json
{
"type": "object",
"properties": {
"keep": {
"type": "array",
"items": {
"type": "integer"
},
"description": "Suggestions to approve"
},
"remove": {
"type": "array",
"items": {
"type": "integer"
},
"description": "Suggestions to take out"
},
"note": {
"type": "string",
"description": "Said to the people whose fixes are sent back"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/transcripts/fixes/decide' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.decideTranscriptFixes({
body: {}
});Try it
A recording's transcript, with its sync by paragraph and word#
GETGET /v1/recordings/{id}/transcript
A paragraph is machine hearing until a person checks it (`checked`).
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/recordings/rh-7k2m9q4d/transcript'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.recordingTranscript({
id: "rh-7k2m9q4d"
});Try it
Everything that happened to a recording's transcript, newest first#
GETGET /v1/recordings/{id}/transcript/history
Each approved change with who made it and what it changed, paragraph by paragraph: `words` (before and after, and whether the whole paragraph was checked), `checked`, `sync` (where it is heard moved) and `made` (the machine's first hearing).
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
limitintegerquery
curl 'https://api.chassidushub.org/v1/recordings/rh-7k2m9q4d/transcript/history'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.transcriptHistory({
id: "rh-7k2m9q4d"
});Try it
Fix the words of one paragraph of a transcript (a suggestion)#
POSTPOST /v1/recordings/{id}/transcript/fix
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"segment": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"content": {
"type": "string"
},
"complete": {
"type": "boolean",
"description": "false: only some words were fixed; the paragraph stays machine hearing (default true)"
}
},
"required": [
"segment",
"content"
]
}curl -X POST 'https://api.chassidushub.org/v1/recordings/rh-7k2m9q4d/transcript/fix' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"segment":"rh-7k2m9q4d","content":"<content>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.fixTranscript({
id: "rh-7k2m9q4d",
body: {
segment: "rh-7k2m9q4d",
content: "<content>"
}
});Try it
The Rebbe is saying this line now: set a paragraph (or word) at atMs, lock it, move what follows#
POSTPOST /v1/recordings/{id}/sync/anchor
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"segment": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"atMs": {
"type": "integer"
},
"word": {
"type": "integer"
}
},
"required": [
"segment",
"atMs"
]
}curl -X POST 'https://api.chassidushub.org/v1/recordings/rh-7k2m9q4d/sync/anchor' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"segment":"rh-7k2m9q4d","atMs":1}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.anchorSync({
id: "rh-7k2m9q4d",
body: {
segment: "rh-7k2m9q4d",
atMs: 1
}
});Try it
The sync is right: mark every paragraph checked#
POSTPOST /v1/recordings/{id}/sync/confirm
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl -X POST 'https://api.chassidushub.org/v1/recordings/rh-7k2m9q4d/sync/confirm' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.confirmSync({
id: "rh-7k2m9q4d"
});Try it
Several recordings' synced hanachos at once (a farbrengen's parts), by recording; those with none are left out#
GETGET /v1/recordings/batch/hanacha
Parameters
idsstringqueryrequiredThe recordings
curl 'https://api.chassidushub.org/v1/recordings/batch/hanacha?ids=%3Cids%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.recordingsHanacha({
ids: "<ids>"
});Try it
The hanacha synced to this recording, paragraph by paragraph#
GETGET /v1/recordings/{id}/hanacha
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/recordings/rh-7k2m9q4d/hanacha'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.recordingHanacha({
id: "rh-7k2m9q4d"
});Try it
Machine#
Asking the machines to read a scan or transcribe a recording, and their queue
- GET
/v1/machineWhat waits for the machines (OCR, transcription), what is left for them, and what they did this week - GET
/v1/machine/trainingThe next Rebbe Whisper's training data so far: every transcript paragraph of the Rebbe speaking that a person checked or fixed, waiting fixes too, as clips - GET
/v1/machine/to-checkWhat the machines wrote that no person has checked yet: farbrengens with unchecked transcript paragraphs, scans with pages read by OCR and not yet proofread, pages whose words a machine read with segments nobody checked, the newest first - GET
/v1/machine/training/clipsThe training clips, one JSON object a line, as the training script reads them (audio, start, end, text, split, quality, review) - GET
/v1/machine/requestsRequests for the machines, the waiting ones in the order they are taken - POST
/v1/machine/requestsAsk the machine to read a scan (ocr) or transcribe a recording (transcript)
What waits for the machines (OCR, transcription), what is left for them, and what they did this week#
GETGET /v1/machine
curl 'https://api.chassidushub.org/v1/machine'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.machineSummary();Try it
The next Rebbe Whisper's training data so far: every transcript paragraph of the Rebbe speaking that a person checked or fixed, waiting fixes too, as clips#
GETGET /v1/machine/training
Hours and clips (gold: words and timing checked by a person; silver: words checked, timing by machine; review: how many are checked, fixed in part, or waiting for review), train and test hours, what was left out and why, and with since, the hours checked since then.
Parameters
sincestringqueryA date: also count the hours checked since then
curl 'https://api.chassidushub.org/v1/machine/training'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.trainingSummary();Try it
What the machines wrote that no person has checked yet: farbrengens with unchecked transcript paragraphs, scans with pages read by OCR and not yet proofread, pages whose words a machine read with segments nobody checked, the newest first#
GETGET /v1/machine/to-check
Parameters
limitintegerqueryHow many (at most 200)
curl 'https://api.chassidushub.org/v1/machine/to-check'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.machineToCheck();Try it
The training clips, one JSON object a line, as the training script reads them (audio, start, end, text, split, quality, review)#
GETGET /v1/machine/training/clips
Parameters
carried1queryWith 1: fixed paragraphs cut by the word times the fix carried over too (marked timing: carried), for a training run that aligns them again
curl 'https://api.chassidushub.org/v1/machine/training/clips'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.trainingClips();Try it
Requests for the machines, the waiting ones in the order they are taken#
GETGET /v1/machine/requests
Parameters
kindocr | transcriptquerystatuswaiting | running | done | failedqueryitemstringqueryRequests for one item
itemsstringqueryIds, comma separated (up to 100)
limitintegerqueryHow many (at most 200)
curl 'https://api.chassidushub.org/v1/machine/requests'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.machineRequests();Try it
Ask the machine to read a scan (ocr) or transcribe a recording (transcript)#
POSTPOST /v1/machine/requests
Free CPU engines only; what they make is labelled as machine output until people check it. Asking for what already waits joins that request (200). Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"kind": {
"enum": [
"ocr",
"transcript"
]
},
"item": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
}
},
"required": [
"kind",
"item"
]
}curl -X POST 'https://api.chassidushub.org/v1/machine/requests' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"kind":"ocr","item":"rh-7k2m9q4d"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.requestMachineWork({
body: {
kind: "ocr",
item: "rh-7k2m9q4d"
}
});Try it
Files#
File bytes (while their rights allow), page images, uploads
- GET
/v1/files/batchSeveral files at once, in the order asked (missing ones left out) - GET
/v1/files/{sha256}A file's size, rights and address, what was made from it, and its page fix - GET
/v1/files/{sha256}/similarHeld files that look like this one (the same scan or recording in other bytes): a machine's guess - GET
/v1/page-fixes/drive/{id}What a PDF on Google Drive needs to read straight, by its Drive id, or the reading copy to open instead - GET
/v1/drive/{id}A Google Drive file the catalog links to (a hanacha's PDF, an Otzros scan), read for the site's reader and player - GET
/objects/{sha256}A file's bytes, while its rights let it be served - GET
/manifests/{collection}/{name}A published manifest: reading copies, page fixes (facts about files, open like the catalog) - GET
/v1/scans/{id}/pagesA served scan's page images and thumbnails, and its IIIF manifest - POST
/v1/uploadsAdd a file: a recording of a farbrengen; a hanacha's PDF for a farbrengen or sicha; a scan (another scan of a printing, a new printing of a sefer, a teshura); or other material (a new sefer, a letter, a document) - POST
/v1/uploads/checkBefore an upload: whether we have it (its sha256, a few page hashes) and what it likely is - POST
/v1/uploads/proposeBefore adding something new: the machine's guess of what it is and where it belongs, from its name (a date in it, words of a title), and files already held that look like it - GET
/v1/files/{sha256}/aboutA file's own page: its rights, where it came from, what was made from it, and what uses it - GET
/v1/coversSefarim's covers, drawn from their title pages, while their PDFs are served or linked - GET
/v1/works/{id}/coverA sefer's cover, the page a person chose, and the PDFs (served, or linked) its title page may be chosen from
Several files at once, in the order asked (missing ones left out)#
GETGET /v1/files/batch
Parameters
idsstringqueryrequiredThe files
curl 'https://api.chassidushub.org/v1/files/batch?ids=%3Cids%3E'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getFiles({
ids: "<ids>"
});Try it
A file's size, rights and address, what was made from it, and its page fix#
GETGET /v1/files/{sha256}
Parameters
sha256stringpathrequiredA file, named by its sha256
curl 'https://api.chassidushub.org/v1/files/<sha256>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getFile({
sha256: "<sha256>"
});Try it
Held files that look like this one (the same scan or recording in other bytes): a machine's guess#
GETGET /v1/files/{sha256}/similar
Parameters
sha256stringpathrequiredA file, named by its sha256
curl 'https://api.chassidushub.org/v1/files/<sha256>/similar'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.similarFiles({
sha256: "<sha256>"
});Try it
What a PDF on Google Drive needs to read straight, by its Drive id, or the reading copy to open instead#
GETGET /v1/page-fixes/drive/{id}
Parameters
idstringpathrequiredA Google Drive file id
curl 'https://api.chassidushub.org/v1/page-fixes/drive/<id>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.driveFix({
id: "<id>"
});Try it
A Google Drive file the catalog links to (a hanacha's PDF, an Otzros scan), read for the site's reader and player#
GETGET /v1/drive/{id}
Only files an item links to. Supports Range requests; the whole file is kept at the edge for a week. Files over the size ChassidusHub passes on (300 MB) answer 413.
Parameters
idstringpathrequiredA Google Drive file id
curl 'https://api.chassidushub.org/v1/drive/<id>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.driveFile({
id: "<id>"
});Try it
A file's bytes, while its rights let it be served#
GETGET /objects/{sha256}
Supports Range requests. `X-Credit` carries the credit the rights ask for.
Parameters
sha256stringpathrequiredA file, named by its sha256
curl 'https://api.chassidushub.org/objects/<sha256>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getObject({
sha256: "<sha256>"
});Try it
A published manifest: reading copies, page fixes (facts about files, open like the catalog)#
GETGET /manifests/{collection}/{name}
Parameters
collectionstringpathrequirednamestringpathrequiredends in .json
curl 'https://api.chassidushub.org/manifests/<collection>/<name>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getManifest({
collection: "<collection>",
name: "<name>"
});Try it
A served scan's page images and thumbnails, and its IIIF manifest#
GETGET /v1/scans/{id}/pages
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/scans/rh-7k2m9q4d/pages'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.scanPages({
id: "rh-7k2m9q4d"
});Try it
Add a file: a recording of a farbrengen; a hanacha's PDF for a farbrengen or sicha; a scan (another scan of a printing, a new printing of a sefer, a teshura); or other material (a new sefer, a letter, a document)#
POSTPOST /v1/uploads
The file is the body, with its Content-Type (audio/…, application/pdf). A recording or hanacha may name a farbrengen the catalog lacks (eventTitle and eventDate) instead of `for`. New accounts wait a day, and everyone adds so many a day. Signed in: an API token with the write scope, or the site's session.
Parameters
whatrecording | hanacha | scan | documentqueryrequiredWhat it is
forstringqueryThe farbrengen, sicha, sefer, printing or Teshuros set it is added to
eventTitlestringqueryFor a recording or hanacha of a farbrengen the catalog lacks: its name
eventDatestringqueryWith eventTitle: its date key
kindbilti-mugah | mugah | maamar | hagahos | hosofos | english | otherqueryFor a hanacha: what kind
setstringqueryFor a document: the set it belongs in
authorstringqueryFor a new sefer: its author
genrestringqueryFor a new sefer: its genre
unitstringqueryFor a letter: the letter the catalog has that it reproduces
rightsmine | free | public-domain | unsurequeryrequiredWhat you know of its rights
asscan-of | printing | teshura | sefer | letter | documentqueryFor a scan: scan-of, printing or teshura. For a document: sefer, letter or document
titlestringqueryIts name
publicationstringqueryFor scan-of: the printing
publisherstringqueryFor a printing
yearstringqueryFor a printing: a Hebrew or civil year
printingintegerqueryFor a printing: 1 for the first
familiesstringqueryFor a teshura: its families, as printed
simchastringqueryFor a teshura: wedding, bar-mitzvah, and so on
datestringqueryFor a teshura: the simcha's date key; for a letter or document, its date
Body application/octet-streamrequired
{
"type": "string",
"format": "binary"
}curl -X POST 'https://api.chassidushub.org/v1/uploads?what=recording&rights=mine' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/pdf' --data-binary @fileimport { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.upload({
what: "recording",
rights: "mine",
body: file,
contentType: "application/pdf"
});Before an upload: whether we have it (its sha256, a few page hashes) and what it likely is#
POSTPOST /v1/uploads/check
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"for": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"sha256": {
"type": "string"
},
"pageHashes": {
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
},
"title": {
"type": "string"
}
},
"required": [
"for"
]
}curl -X POST 'https://api.chassidushub.org/v1/uploads/check' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"for":"rh-7k2m9q4d"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.checkUpload({
body: {
for: "rh-7k2m9q4d"
}
});Try it
Before adding something new: the machine's guess of what it is and where it belongs, from its name (a date in it, words of a title), and files already held that look like it#
POSTPOST /v1/uploads/propose
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"what": {
"enum": [
"hanacha",
"recording",
"document"
]
},
"name": {
"type": "string",
"description": "Its file name or title"
},
"sha256": {
"type": "string",
"description": "A file, named by its sha256",
"pattern": "^[0-9a-f]{64}$"
},
"pageHashes": {
"type": "array",
"items": {
"oneOf": [
{
"type": "string"
},
{
"type": "null"
}
]
}
}
},
"required": [
"what"
]
}curl -X POST 'https://api.chassidushub.org/v1/uploads/propose' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"what":"hanacha"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.proposeUpload({
body: {
what: "hanacha"
}
});Try it
A file's own page: its rights, where it came from, what was made from it, and what uses it#
GETGET /v1/files/{sha256}/about
Parameters
sha256stringpathrequiredA file, named by its sha256
limitintegerqueryHow many (at most 500)
curl 'https://api.chassidushub.org/v1/files/<sha256>/about'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.fileAbout({
sha256: "<sha256>"
});Try it
Sefarim's covers, drawn from their title pages, while their PDFs are served or linked#
GETGET /v1/covers
A cover is `machine: true` until a person chose its page. A cover drawn from a PDF ChassidusHub only links to is served; the PDF is not (its file page links to the source).
Parameters
idsstringqueryThe sefarim
curl 'https://api.chassidushub.org/v1/covers'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.covers();Try it
A sefer's cover, the page a person chose, and the PDFs (served, or linked) its title page may be chosen from#
GETGET /v1/works/{id}/cover
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/works/rh-7k2m9q4d/cover'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.workCover({
id: "rh-7k2m9q4d"
});Try it
Suggestions#
Every change is a suggestion, checked and reviewed
- POST
/v1/entities/{id}/restoreSuggest restoring an earlier version of an item - GET
/v1/suggestionsSuggestions, oldest sent first, by status or author; with `state`, the list of conversations, newest first (numbers, reviewers, approvals, the issues each closes) with counts - POST
/v1/suggestionsStart a suggestion (a draft): add items to it, then submit it - POST
/v1/suggestions/quickSuggest a fix in one step: a new version of one item, with a few words on why, sent for review - GET
/v1/suggestions/{id}The review view: each item before and after, clashes with main, and the reviewer's advice (machine-written, `machine: true`). A page of items at a time (`entries`, from `offset`), with `total`, `next` (the offset of the next page, or null) and, with summary=1, `summary`: the items grouped by how they change ("500 units: links on the media proxy became links on Drive"), with a few examples of each - PATCH
/v1/suggestions/{id}Change the title or description of your suggestion (@mentions and "Fixes #12" are read again) - GET
/v1/suggestions/{id}/conversationA suggestion's timeline (comments, reviews, events), the reviewers asked, and the issues it closes - POST
/v1/suggestions/{id}/commentsComment on a suggestion, answer a comment, or comment on one field of one item - POST
/v1/suggestions/{id}/reviewsReview: approve (it goes into the catalog, where you may merge it), request changes (sent back), or comment; with comments on fields - POST
/v1/suggestions/{id}/review-requestsAsk people to review (asking again asks again) - DELETE
/v1/suggestions/{id}/review-requests/{username}Stop asking someone to review - PUT
/v1/suggestions/{id}/itemsAdd or change one item in a draft suggestion (data null deletes it) - POST
/v1/suggestions/{id}/submitSend for review (runs the automatic checks) - POST
/v1/suggestions/{id}/approveApprove and merge (keepers of its sets, stewards) - POST
/v1/suggestions/{id}/send-backSend back with a note - POST
/v1/suggestions/{id}/review-liveReview a live change after it went live: keep it (approve) or undo it (revert) - POST
/v1/suggestions/{id}/withdrawWithdraw your suggestion - POST
/v1/suggestions/{id}/reopenUndo a withdrawal: your suggestion is open for review again (its checks run again) - POST
/v1/suggestions/{id}/revertUndo a merged suggestion (a new suggestion that reverses it) - POST
/v1/suggestions/shaarA sefer's shaar, the whole file, sent for review; a file the catalog cannot read is refused with each line that is wrong (`detail.problems`) - POST
/v1/suggestions/wordsA page's words fixed segment by segment: one segment's new words, a segment added after it or taken out, a page's first words, or a machine's segment checked as right (`check`), sent for review - POST
/v1/suggestions/combineCombine several of your own suggestions into one, as a pull request holds many commits - POST
/v1/suggestions/contents-mapMap pages of a publication to the unit they hold (an existing unit, a new one, or words) - POST
/v1/comments/{id}/resolveResolve (or unresolve) a comment on a suggestion's field
Suggest restoring an earlier version of an item#
POSTPOST /v1/entities/{id}/restore
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"rev": {
"type": "integer",
"description": "The revision to restore"
}
},
"required": [
"rev"
]
}curl -X POST 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/restore' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"rev":1}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.restoreItem({
id: "rh-7k2m9q4d",
body: {
rev: 1
}
});Try it
Suggestions, oldest sent first, by status or author; with `state`, the list of conversations, newest first (numbers, reviewers, approvals, the issues each closes) with counts#
GETGET /v1/suggestions
Parameters
statusdraft | open | merged | sent_back | withdrawnquerystateopen | closed | allqueryThe conversation list: open (waiting or sent back) or closed (merged or withdrawn)
authorstringqueryAn account id, or (with state) a handle
reviewerstringqueryWith state: asked to review, or reviewed (a handle)
qstringqueryWith state: words in the title, or #number
aboutstringqueryWith state: only suggestions that change these items, or what is in them (a sefer's sichos and their texts, a sicha's paragraphs, a farbrengen's sichos)
postReviewtrue | falsequerytrue: live changes waiting to be reviewed after
limitintegerqueryHow many (at most 500)
cursorstringqueryThe `next` of the page before
curl 'https://api.chassidushub.org/v1/suggestions'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
for await (const item of rh.all('listSuggestions', {})) {
console.log(item);
}Try it
Start a suggestion (a draft): add items to it, then submit it#
POSTPOST /v1/suggestions
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"project": {
"type": "integer"
}
},
"required": [
"title"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"title":"Fix the date"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.createSuggestion({
body: {
title: "Fix the date"
}
});Try it
Suggest a fix in one step: a new version of one item, with a few words on why, sent for review#
POSTPOST /v1/suggestions/quick
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"entityId": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"data": {
"type": "object",
"additionalProperties": true,
"description": "The item's whole new data"
},
"title": {
"type": "string",
"maxLength": 200
},
"note": {
"type": "string",
"maxLength": 2000
}
},
"required": [
"entityId",
"data"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/quick' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"entityId":"rh-7k2m9q4d","data":{}}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.suggestFix({
body: {
entityId: "rh-7k2m9q4d",
data: {}
}
});Try it
The review view: each item before and after, clashes with main, and the reviewer's advice (machine-written, `machine: true`). A page of items at a time (`entries`, from `offset`), with `total`, `next` (the offset of the next page, or null) and, with summary=1, `summary`: the items grouped by how they change ("500 units: links on the media proxy became links on Drive"), with a few examples of each#
GETGET /v1/suggestions/{id}
No account needed; signed in, a little more.
Parameters
idintegerpathrequiredThe suggestion
offsetintegerqueryItems to skip: the `next` of the page before
limitintegerqueryHow many (at most 200)
summary1queryWith 1: also `summary`, every item grouped by how it changes (all of them are read and compared for it)
brief1queryWith 1: each item's facts, not its words (`before` and `after` without `body`; what changed is whole in `changes`), for a feed
curl 'https://api.chassidushub.org/v1/suggestions/1'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getSuggestion({
id: 1
});Try it
Change the title or description of your suggestion (@mentions and "Fixes #12" are read again)#
PATCHPATCH /v1/suggestions/{id}
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/json
{
"type": "object",
"properties": {
"title": {
"type": "string",
"maxLength": 200
},
"description": {
"type": "string"
}
}
}curl -X PATCH 'https://api.chassidushub.org/v1/suggestions/1' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.editSuggestion({
id: 1,
body: {}
});Try it
A suggestion's timeline (comments, reviews, events), the reviewers asked, and the issues it closes#
GETGET /v1/suggestions/{id}/conversation
No account needed; signed in, a little more.
Parameters
idintegerpathrequiredThe suggestion
curl 'https://api.chassidushub.org/v1/suggestions/1/conversation'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.suggestionConversation({
id: 1
});Try it
Comment on a suggestion, answer a comment, or comment on one field of one item#
POSTPOST /v1/suggestions/{id}/comments
@handles are told (their inbox), and #12 links to that suggestion or issue. Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/jsonrequired
{
"type": "object",
"properties": {
"body": {
"type": "string",
"minLength": 1,
"maxLength": 10000
},
"parent": {
"type": "integer",
"description": "The comment this answers"
},
"anchor": {
"type": "object",
"properties": {
"entity": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"field": {
"type": "string"
}
},
"required": [
"entity",
"field"
]
}
},
"required": [
"body"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/comments' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"<body>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.commentOnSuggestion({
id: 1,
body: {
body: "<body>"
}
});Try it
Review: approve (it goes into the catalog, where you may merge it), request changes (sent back), or comment; with comments on fields#
POSTPOST /v1/suggestions/{id}/reviews
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/jsonrequired
{
"type": "object",
"properties": {
"verdict": {
"enum": [
"approve",
"request_changes",
"comment"
]
},
"body": {
"type": "string"
},
"comments": {
"type": "array",
"items": {
"type": "object",
"properties": {
"entity": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"field": {
"type": "string"
},
"body": {
"type": "string"
}
},
"required": [
"entity",
"field",
"body"
]
}
},
"resolutions": {
"type": "object",
"additionalProperties": true,
"description": "For each item, how each clashing field is settled: {item: {field: {take: \"ours\" (the site) | \"theirs\" (the suggestion)}}}; `*` stands for every item or every field not named"
}
},
"required": [
"verdict"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/reviews' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"verdict":"approve"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.reviewSuggestion({
id: 1,
body: {
verdict: "approve"
}
});Try it
Ask people to review (asking again asks again)#
POSTPOST /v1/suggestions/{id}/review-requests
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/jsonrequired
{
"type": "object",
"properties": {
"reviewers": {
"type": "array",
"items": {
"type": "string",
"description": "A handle"
},
"description": "Handles"
}
},
"required": [
"reviewers"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/review-requests' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"reviewers":["<reviewers>"]}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.requestReview({
id: 1,
body: {
reviewers: [
"<reviewers>"
]
}
});Try it
Stop asking someone to review#
DELETEDELETE /v1/suggestions/{id}/review-requests/{username}
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
usernamestringpathrequiredA handle, without the @
curl -X DELETE 'https://api.chassidushub.org/v1/suggestions/1/review-requests/<username>' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.removeReviewRequest({
id: 1,
username: "<username>"
});Try it
Add or change one item in a draft suggestion (data null deletes it)#
PUTPUT /v1/suggestions/{id}/items
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/jsonrequired
{
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"type": {
"type": "string"
},
"data": {
"type": [
"object",
"null"
]
},
"path": {
"type": [
"string",
"null"
]
}
},
"required": [
"type",
"data"
]
}curl -X PUT 'https://api.chassidushub.org/v1/suggestions/1/items' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"type":"<type>","data":{}}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.putSuggestionItem({
id: 1,
body: {
type: "<type>",
data: {}
}
});Try it
Send for review (runs the automatic checks)#
POSTPOST /v1/suggestions/{id}/submit
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/submit' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.submitSuggestion({
id: 1
});Try it
Approve and merge (keepers of its sets, stewards)#
POSTPOST /v1/suggestions/{id}/approve
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/json
{
"type": "object",
"properties": {
"resolutions": {
"type": "object",
"additionalProperties": true,
"description": "For each item, how each clashing field is settled: {item: {field: {take: \"ours\" (the site) | \"theirs\" (the suggestion)}}}; `*` stands for every item or every field not named"
},
"note": {
"type": "string"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/approve' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.approveSuggestion({
id: 1,
body: {}
});Try it
Send back with a note#
POSTPOST /v1/suggestions/{id}/send-back
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/json
{
"type": "object",
"properties": {
"note": {
"type": "string"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/send-back' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.sendBackSuggestion({
id: 1,
body: {}
});Try it
Review a live change after it went live: keep it (approve) or undo it (revert)#
POSTPOST /v1/suggestions/{id}/review-live
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/jsonrequired
{
"type": "object",
"properties": {
"verdict": {
"enum": [
"approve",
"revert"
]
},
"note": {
"type": "string"
}
},
"required": [
"verdict"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/review-live' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"verdict":"approve"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.reviewLive({
id: 1,
body: {
verdict: "approve"
}
});Try it
Withdraw your suggestion#
POSTPOST /v1/suggestions/{id}/withdraw
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/withdraw' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.withdrawSuggestion({
id: 1
});Try it
Undo a withdrawal: your suggestion is open for review again (its checks run again)#
POSTPOST /v1/suggestions/{id}/reopen
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/reopen' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.reopenSuggestion({
id: 1
});Try it
Undo a merged suggestion (a new suggestion that reverses it)#
POSTPOST /v1/suggestions/{id}/revert
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe suggestion
Body application/json
{
"type": "object",
"properties": {
"reason": {
"type": "string"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/1/revert' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.revertSuggestion({
id: 1,
body: {}
});Try it
A sefer's shaar, the whole file, sent for review; a file the catalog cannot read is refused with each line that is wrong (`detail.problems`)#
POSTPOST /v1/suggestions/shaar
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"entityId": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"text": {
"type": "string",
"description": "The whole shaar file"
},
"before": {
"type": "string",
"description": "The file as the person opened it; a change since answers 409"
},
"title": {
"type": "string"
},
"note": {
"type": "string"
}
},
"required": [
"entityId",
"text"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/shaar' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"entityId":"rh-7k2m9q4d","text":"<text>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.suggestShaar({
body: {
entityId: "rh-7k2m9q4d",
text: "<text>"
}
});Try it
A page's words fixed segment by segment: one segment's new words, a segment added after it or taken out, a page's first words, or a machine's segment checked as right (`check`), sent for review#
POSTPOST /v1/suggestions/words
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"entityId": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"change": {
"enum": [
"edit",
"add",
"remove",
"start",
"check"
]
},
"version": {
"type": "string"
},
"segment": {
"type": "string"
},
"text": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
},
"description": "Runs: { text, marks?, href? }, { note }, { marker }, { br: true }, { eol, split?, page?, box? }"
},
"before": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
},
"description": "The segment as the person saw it; a change since answers 409"
},
"kind": {
"enum": [
"paragraph",
"heading",
"verse",
"item"
]
},
"language": {
"type": "string"
},
"title": {
"type": "string"
},
"note": {
"type": "string"
}
},
"required": [
"entityId",
"change"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/words' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"entityId":"rh-7k2m9q4d","change":"edit"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.suggestWords({
body: {
entityId: "rh-7k2m9q4d",
change: "edit"
}
});Try it
Combine several of your own suggestions into one, as a pull request holds many commits#
POSTPOST /v1/suggestions/combine
Their changes are applied in the order they were made; changes to different words of one text are all kept, and where a later change rewrites an earlier one the later one stands. The suggestions combined are withdrawn. Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"suggestions": {
"type": "array",
"items": {
"type": "integer"
},
"description": "Their ids (2 to 100), all yours and not yet approved"
},
"title": {
"type": "string",
"maxLength": 200
}
},
"required": [
"suggestions"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/combine' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"suggestions":[1]}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.combineSuggestions({
body: {
suggestions: [
1
]
}
});Try it
Map pages of a publication to the unit they hold (an existing unit, a new one, or words)#
POSTPOST /v1/suggestions/contents-map
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"publication": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"pages": {
"type": "object",
"properties": {
"from": {
"type": "integer"
},
"to": {
"type": "integer"
},
"scheme": {
"enum": [
"printed",
"pdf"
]
}
},
"required": [
"from",
"to"
]
},
"unit": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"newUnit": {
"type": "object",
"properties": {
"work": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"label": {
"type": "object",
"additionalProperties": true
},
"date": {
"type": "string"
}
}
},
"label": {
"type": "object",
"additionalProperties": true
}
},
"required": [
"publication",
"pages"
]
}curl -X POST 'https://api.chassidushub.org/v1/suggestions/contents-map' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"publication":"rh-7k2m9q4d","pages":{"from":1,"to":1}}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.mapContents({
body: {
publication: "rh-7k2m9q4d",
pages: {
from: 1,
to: 1
}
}
});Try it
Resolve (or unresolve) a comment on a suggestion's field#
POSTPOST /v1/comments/{id}/resolve
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe comment
Body application/json
{
"type": "object",
"properties": {
"resolved": {
"type": "boolean",
"description": "false to unresolve"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/comments/1/resolve' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.resolveComment({
id: 1,
body: {}
});Try it
Organize#
Moving, renaming, ordering, merging and splitting: the catalog's tree put in order, as suggestions
- GET
/v1/treeThe catalog as a tree: the top sets (or one set or sefer), the sets and items under them, and how much each holds - POST
/v1/organize/previewWhat a plan of moves, renames, orderings, new sets and merges would change, item by item, saved nowhere - POST
/v1/organizeOrganize the catalog: a plan becomes one suggestion, sent for review (apply: true approves it at once where you may approve it yourself)
The catalog as a tree: the top sets (or one set or sefer), the sets and items under them, and how much each holds#
GETGET /v1/tree
Parameters
rootstringqueryA set or a sefer (work); left out, the top sets
depthintegerqueryHow many levels down
limitintegerqueryHow many (at most 500)
curl 'https://api.chassidushub.org/v1/tree'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.catalogTree();Try it
What a plan of moves, renames, orderings, new sets and merges would change, item by item, saved nowhere#
POSTPOST /v1/organize/preview
Signed in: an API token with the write scope, or the site's session.
Body application/json
{
"$ref": "#/components/schemas/OrganizePlan"
}curl -X POST 'https://api.chassidushub.org/v1/organize/preview' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"operations":[{"op":null}]}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.previewOrganize({
body: {
operations: [
{
op: null
}
]
}
});Try it
Organize the catalog: a plan becomes one suggestion, sent for review (apply: true approves it at once where you may approve it yourself)#
POSTPOST /v1/organize
Operations: move, move-up, rename, reorder, create-set, delete-set, merge, split, addition, official. Every old path redirects once it is approved; a merged item's paths lead to the item it was merged into. Signed in: an API token with the write scope, or the site's session.
Body application/json
{
"$ref": "#/components/schemas/OrganizePlan"
}curl -X POST 'https://api.chassidushub.org/v1/organize' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"operations":[{"op":null}]}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.organize({
body: {
operations: [
{
op: null
}
]
}
});Try it
Talk#
The conversation on each page
- GET
/v1/entities/{id}/talkAn item's talk page: the conversation about it - POST
/v1/entities/{id}/talkComment on an item's talk page - POST
/v1/comments/{id}/hideHide a comment (its author, or a steward) - PATCH
/v1/comments/{id}Change your own comment (on a talk page, a suggestion or an issue)
An item's talk page: the conversation about it#
GETGET /v1/entities/{id}/talk
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
curl 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/talk'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.itemTalk({
id: "rh-7k2m9q4d"
});Try it
Comment on an item's talk page#
POSTPOST /v1/entities/{id}/talk
Signed in: an API token with the write scope, or the site's session.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/jsonrequired
{
"type": "object",
"properties": {
"body": {
"type": "string",
"minLength": 1,
"maxLength": 10000
},
"parent": {
"type": "integer",
"description": "The comment this answers"
}
},
"required": [
"body"
]
}curl -X POST 'https://api.chassidushub.org/v1/entities/rh-7k2m9q4d/talk' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"<body>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.commentOnItem({
id: "rh-7k2m9q4d",
body: {
body: "<body>"
}
});Try it
Hide a comment (its author, or a steward)#
POSTPOST /v1/comments/{id}/hide
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe comment
curl -X POST 'https://api.chassidushub.org/v1/comments/1/hide' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.hideComment({
id: 1
});Try it
Change your own comment (on a talk page, a suggestion or an issue)#
PATCHPATCH /v1/comments/{id}
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe comment
Body application/jsonrequired
{
"type": "object",
"properties": {
"body": {
"type": "string",
"minLength": 1,
"maxLength": 10000
}
},
"required": [
"body"
]
}curl -X PATCH 'https://api.chassidushub.org/v1/comments/1' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"<body>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.editComment({
id: 1,
body: {
body: "<body>"
}
});Try it
Reports#
Reporting a problem, takedowns, families' requests
- POST
/v1/reportsReport a problem (no account needed: a captcha and an hourly limit instead) - GET
/v1/reportsA set's inbox of reports (stewards, and the set's keepers) - POST
/v1/reports/{id}/closeResolve or dismiss a report (keepers) - POST
/v1/takedownsAsk for a file to stop being served (no account needed); stewards answer within two weeks - POST
/v1/teshuros/{id}/family-requestA family's request that a teshura not be shown (no account needed): its scans stop being served at once, and stewards review it
Report a problem (no account needed: a captcha and an hourly limit instead)#
POSTPOST /v1/reports
No account needed; signed in, a little more.
Body application/jsonrequired
{
"type": "object",
"properties": {
"entityId": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"reason": {
"enum": [
"wrong-fact",
"missing-page",
"bad-scan",
"audio-problem",
"wrong-text",
"duplicate",
"rights",
"offensive",
"other"
]
},
"note": {
"type": "string",
"maxLength": 10000
},
"title": {
"type": "string",
"description": "A title of its own, as an issue",
"maxLength": 200
},
"captcha": {
"type": "string",
"description": "A Turnstile token, when not signed in"
}
},
"required": [
"reason"
]
}curl -X POST 'https://api.chassidushub.org/v1/reports' \
-H 'Content-Type: application/json' \
-d '{"reason":"wrong-fact"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.report({
body: {
reason: "wrong-fact"
}
});Try it
A set's inbox of reports (stewards, and the set's keepers)#
GETGET /v1/reports
Signed in: an API token (read scope is enough), or the site's session.
Parameters
setstringqueryA set
statusopen | resolved | dismissedquery
curl 'https://api.chassidushub.org/v1/reports' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.listReports();Try it
Resolve or dismiss a report (keepers)#
POSTPOST /v1/reports/{id}/close
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe report
Body application/jsonrequired
{
"type": "object",
"properties": {
"outcome": {
"enum": [
"resolved",
"dismissed"
]
},
"changeset": {
"type": "integer",
"description": "The suggestion that fixed it"
},
"note": {
"type": "string"
}
},
"required": [
"outcome"
]
}curl -X POST 'https://api.chassidushub.org/v1/reports/1/close' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"outcome":"resolved"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.closeReport({
id: 1,
body: {
outcome: "resolved"
}
});Try it
Ask for a file to stop being served (no account needed); stewards answer within two weeks#
POSTPOST /v1/takedowns
Body application/jsonrequired
{
"type": "object",
"properties": {
"target": {
"type": "string",
"description": "The address of its page, an id, or the file address"
},
"name": {
"type": "string"
},
"email": {
"type": "string"
},
"relation": {
"enum": [
"rights-holder",
"family",
"representative",
"other"
]
},
"statement": {
"type": "string",
"minLength": 10,
"maxLength": 4000
},
"captcha": {
"type": "string"
}
},
"required": [
"target",
"name",
"email",
"relation",
"statement"
]
}curl -X POST 'https://api.chassidushub.org/v1/takedowns' \
-H 'Content-Type: application/json' \
-d '{"target":"<target>","name":"<name>","email":"<email>","relation":"rights-holder","statement":"<statement>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.requestTakedown({
body: {
target: "<target>",
name: "<name>",
email: "<email>",
relation: "rights-holder",
statement: "<statement>"
}
});Try it
A family's request that a teshura not be shown (no account needed): its scans stop being served at once, and stewards review it#
POSTPOST /v1/teshuros/{id}/family-request
No account needed; signed in, a little more.
Parameters
idstringpathrequiredA permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)
Body application/json
{
"type": "object",
"properties": {
"relation": {
"type": "string"
},
"note": {
"type": "string"
},
"contact": {
"type": "string"
},
"captcha": {
"type": "string"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/teshuros/rh-7k2m9q4d/family-request' \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.familyRequest({
id: "rh-7k2m9q4d",
body: {}
});Try it
Issues#
Reports kept like issues: titles, labels, assignees, comments, closing
- GET
/v1/issuesIssues, newest first, with open and closed counts; private ones only for those who may read them - POST
/v1/issuesOpen an issue (about an item, or the catalog at large) - GET
/v1/issues/templatesThe kinds of issue and the words each starts with - GET
/v1/issues/{number}An issue, its timeline, what the reader may do, and the suggestions that close it - PATCH
/v1/issues/{number}Change its title or words (its author, keepers, stewards) - POST
/v1/issues/{number}/stateClose as completed or not planned, or reopen - PUT
/v1/issues/{number}/labelsSet its labels (keepers, stewards, trusted people) - PUT
/v1/issues/{number}/assigneesSet who it is assigned to (yourself; others when you may triage) - POST
/v1/issues/{number}/visibilityMake it private or public (stewards and keepers) - POST
/v1/issues/{number}/commentsComment on an issue, or answer a comment - GET
/v1/labelsEvery label and how many open issues carry it - POST
/v1/labelsMake a label (stewards)
Issues, newest first, with open and closed counts; private ones only for those who may read them#
GETGET /v1/issues
No account needed; signed in, a little more.
Parameters
stateopen | closed | allqueryopen (the default), closed or all
labelstringqueryLabel names, comma separated
typewrong-fact | missing-page | bad-scan | audio-problem | wrong-text | duplicate | rights | offensive | otherqueryThe kind of report
setstringqueryOnly about items in this set
entitystringqueryOnly about this item
assigneestringqueryA handle, or none
authorstringqueryA handle
qstringqueryWords, or #number
beforeintegerqueryDeprecated: the same as a cursor, as a number
limitintegerqueryHow many (at most 100)
cursorstringqueryThe `next` of the page before
curl 'https://api.chassidushub.org/v1/issues'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
for await (const item of rh.all('listIssues', {})) {
console.log(item);
}Try it
Open an issue (about an item, or the catalog at large)#
POSTPOST /v1/issues
Reports of rights or of something offensive are private: stewards and the set's keepers read them. Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"body": {
"type": "string",
"maxLength": 10000
},
"type": {
"enum": [
"wrong-fact",
"missing-page",
"bad-scan",
"audio-problem",
"wrong-text",
"duplicate",
"rights",
"offensive",
"other"
]
},
"entityId": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"labels": {
"type": "array",
"items": {
"type": "string"
}
},
"private": {
"type": "boolean",
"description": "Keep it for stewards and keepers"
}
},
"required": [
"title"
]
}curl -X POST 'https://api.chassidushub.org/v1/issues' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"title":"Fix the date"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.openIssue({
body: {
title: "Fix the date"
}
});Try it
The kinds of issue and the words each starts with#
GETGET /v1/issues/templates
curl 'https://api.chassidushub.org/v1/issues/templates'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.issueTemplates();Try it
An issue, its timeline, what the reader may do, and the suggestions that close it#
GETGET /v1/issues/{number}
No account needed; signed in, a little more.
Parameters
numberintegerpathrequiredThe issue
curl 'https://api.chassidushub.org/v1/issues/1'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getIssue({
number: 1
});Try it
Change its title or words (its author, keepers, stewards)#
PATCHPATCH /v1/issues/{number}
Signed in: an API token with the write scope, or the site's session.
Parameters
numberintegerpathrequiredThe issue
Body application/json
{
"type": "object",
"properties": {
"title": {
"type": "string",
"maxLength": 200
},
"body": {
"type": "string"
}
}
}curl -X PATCH 'https://api.chassidushub.org/v1/issues/1' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.editIssue({
number: 1,
body: {}
});Try it
Close as completed or not planned, or reopen#
POSTPOST /v1/issues/{number}/state
Signed in: an API token with the write scope, or the site's session.
Parameters
numberintegerpathrequiredThe issue
Body application/jsonrequired
{
"type": "object",
"properties": {
"state": {
"enum": [
"open",
"completed",
"not_planned"
]
},
"note": {
"type": "string",
"maxLength": 2000
}
},
"required": [
"state"
]
}curl -X POST 'https://api.chassidushub.org/v1/issues/1/state' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"state":"open"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.setIssueState({
number: 1,
body: {
state: "open"
}
});Try it
Set its labels (keepers, stewards, trusted people)#
PUTPUT /v1/issues/{number}/labels
Signed in: an API token with the write scope, or the site's session.
Parameters
numberintegerpathrequiredThe issue
Body application/jsonrequired
{
"type": "object",
"properties": {
"labels": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"labels"
]
}curl -X PUT 'https://api.chassidushub.org/v1/issues/1/labels' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"labels":["<labels>"]}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.setIssueLabels({
number: 1,
body: {
labels: [
"<labels>"
]
}
});Try it
Set who it is assigned to (yourself; others when you may triage)#
PUTPUT /v1/issues/{number}/assignees
Signed in: an API token with the write scope, or the site's session.
Parameters
numberintegerpathrequiredThe issue
Body application/jsonrequired
{
"type": "object",
"properties": {
"assignees": {
"type": "array",
"items": {
"type": "string",
"description": "A handle"
}
}
},
"required": [
"assignees"
]
}curl -X PUT 'https://api.chassidushub.org/v1/issues/1/assignees' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"assignees":["<assignees>"]}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.setIssueAssignees({
number: 1,
body: {
assignees: [
"<assignees>"
]
}
});Try it
Make it private or public (stewards and keepers)#
POSTPOST /v1/issues/{number}/visibility
Signed in: an API token with the write scope, or the site's session.
Parameters
numberintegerpathrequiredThe issue
Body application/jsonrequired
{
"type": "object",
"properties": {
"private": {
"type": "boolean"
}
},
"required": [
"private"
]
}curl -X POST 'https://api.chassidushub.org/v1/issues/1/visibility' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"private":true}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.setIssueVisibility({
number: 1,
body: {
private: true
}
});Try it
Comment on an issue, or answer a comment#
POSTPOST /v1/issues/{number}/comments
@handles are told (their inbox), and #12 links to that suggestion or issue. Signed in: an API token with the write scope, or the site's session.
Parameters
numberintegerpathrequiredThe issue
Body application/jsonrequired
{
"type": "object",
"properties": {
"body": {
"type": "string",
"minLength": 1,
"maxLength": 10000
},
"parent": {
"type": "integer",
"description": "The comment this answers"
}
},
"required": [
"body"
]
}curl -X POST 'https://api.chassidushub.org/v1/issues/1/comments' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"<body>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.commentOnIssue({
number: 1,
body: {
body: "<body>"
}
});Try it
Every label and how many open issues carry it#
GETGET /v1/labels
curl 'https://api.chassidushub.org/v1/labels'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.listLabels();Try it
Make a label (stewards)#
POSTPOST /v1/labels
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"name": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9 -]{0,38}[a-z0-9]$"
},
"description": {
"type": "string"
},
"color": {
"type": "string",
"description": "Six hex digits",
"pattern": "^[0-9a-f]{6}$"
}
},
"required": [
"name"
]
}curl -X POST 'https://api.chassidushub.org/v1/labels' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"<name>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.createLabel({
body: {
name: "<name>"
}
});Try it
People#
Handles and profiles; people and conversations to @mention and #mention
- GET
/v1/peoplePeople to @mention: handles that start with, or names that contain, what is typed; those in the conversation first - GET
/v1/people/{username}A person's public page: who they are, their counts and recent activity (an old handle finds them too, with `movedFrom`) - GET
/v1/threadsSuggestions and issues to #mention, by number or words - GET
/v1/threads/{number}Which of the two #12 is: a suggestion or an issue, and its id
People to @mention: handles that start with, or names that contain, what is typed; those in the conversation first#
GETGET /v1/people
Parameters
qstringqueryWhat follows the @
idsstringqueryAccount ids, comma separated (at most 100): who each is, instead of a search
threadstringquerychangeset:<id> or report:<id>
limitintegerqueryHow many (at most 20)
curl 'https://api.chassidushub.org/v1/people'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.searchPeople();Try it
A person's public page: who they are, their counts and recent activity (an old handle finds them too, with `movedFrom`)#
GETGET /v1/people/{username}
Parameters
usernamestringpathrequiredA handle, without the @
limitintegerqueryHow many (at most 100)
curl 'https://api.chassidushub.org/v1/people/<username>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getProfile({
username: "<username>"
});Try it
Suggestions and issues to #mention, by number or words#
GETGET /v1/threads
No account needed; signed in, a little more.
Parameters
qstringqueryWhat follows the #
limitintegerqueryHow many (at most 20)
curl 'https://api.chassidushub.org/v1/threads'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.searchThreads();Try it
Which of the two #12 is: a suggestion or an issue, and its id#
GETGET /v1/threads/{number}
No account needed; signed in, a little more.
Parameters
numberintegerpathrequiredThe number after #
curl 'https://api.chassidushub.org/v1/threads/1'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.threadByNumber({
number: 1
});Try it
Inbox#
What concerns you: mentions, review requests, assignments, what you follow
- GET
/v1/inboxYour inbox, newest first: mentions, review requests, assignments and what you follow - GET
/v1/inbox/countHow many inbox lines are unread - POST
/v1/inbox/readMark inbox lines read (or unread): by id, by conversation, or all
Your inbox, newest first: mentions, review requests, assignments and what you follow#
GETGET /v1/inbox
Signed in: an API token (read scope is enough), or the site's session.
Parameters
filterunread | all | mention | review_requested | assigned | author | comment | review | state | followedqueryunread, all, or one reason
beforestringqueryDeprecated: lines older than this time; use cursor
limitintegerqueryHow many (at most 100)
cursorstringqueryThe `next` of the page before
curl 'https://api.chassidushub.org/v1/inbox' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
for await (const item of rh.all('inbox', {})) {
console.log(item);
}Try it
How many inbox lines are unread#
GETGET /v1/inbox/count
Signed in: an API token (read scope is enough), or the site's session.
curl 'https://api.chassidushub.org/v1/inbox/count' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.inboxCount();Try it
Mark inbox lines read (or unread): by id, by conversation, or all#
POSTPOST /v1/inbox/read
Signed in: an API token with the write scope, or the site's session.
Body application/json
{
"type": "object",
"properties": {
"ids": {
"type": "array",
"items": {
"type": "integer"
}
},
"subject": {
"type": "object",
"properties": {
"kind": {
"enum": [
"changeset",
"report",
"entity",
"project"
]
},
"id": {
"type": "string"
}
},
"required": [
"kind",
"id"
]
},
"all": {
"type": "boolean"
},
"unread": {
"type": "boolean",
"description": "true: mark them unread"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/inbox/read' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.markInboxRead({
body: {}
});Try it
Projects#
Group efforts through a gap, the Missing board
- GET
/v1/missingThe Missing board: farbrengens without a recording or a text, sefarim without a scan, files lost upstream - GET
/v1/projectsProjects working through a gap, with their progress - POST
/v1/projectsOpen a project on a gap (farbrengens without recordings or texts, recordings to sync, pages to proofread) - GET
/v1/projects/{slug}A project, its progress and what is left to do - POST
/v1/projects/{slug}/nextHand me the next item nobody holds (held for you for a few hours) - POST
/v1/projects/{slug}/releaseLet go of an item you held - POST
/v1/projects/{slug}/closeClose a project (its keepers, stewards)
The Missing board: farbrengens without a recording or a text, sefarim without a scan, files lost upstream#
GETGET /v1/missing
Parameters
kindrecordings | texts | scans | filesqueryrequiredWhat is missing
withinstringqueryFor recordings and texts: a year or a month
limitintegerqueryHow many (at most 500)
curl 'https://api.chassidushub.org/v1/missing?kind=recordings'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.missing({
kind: "recordings"
});Try it
Projects working through a gap, with their progress#
GETGET /v1/projects
Parameters
statusopen | merged | closedquery
curl 'https://api.chassidushub.org/v1/projects'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.listProjects();Try it
Open a project on a gap (farbrengens without recordings or texts, recordings to sync, pages to proofread)#
POSTPOST /v1/projects
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"slug": {
"type": "string",
"pattern": "^[a-z0-9-]+$"
},
"name": {
"type": "string"
},
"goal": {
"type": "string"
},
"set": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"missing": {
"enum": [
"recordings",
"texts",
"sync",
"proofreading"
]
},
"within": {
"type": "string"
},
"scan": {
"type": "string",
"description": "A permanent id: rh- and letters and digits (read forgivingly: RH-7K2M-9Q4D works)",
"pattern": "^[rR][hH]-[0-9A-Za-z-]+$",
"examples": [
"rh-7k2m9q4d"
]
},
"level": {
"enum": [
1,
2
]
}
},
"required": [
"slug",
"name"
]
}curl -X POST 'https://api.chassidushub.org/v1/projects' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"slug":"<slug>","name":"<name>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.createProject({
body: {
slug: "<slug>",
name: "<name>"
}
});Try it
A project, its progress and what is left to do#
GETGET /v1/projects/{slug}
Parameters
slugstringpathrequiredA project's short name
curl 'https://api.chassidushub.org/v1/projects/<slug>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getProject({
slug: "<slug>"
});Try it
Hand me the next item nobody holds (held for you for a few hours)#
POSTPOST /v1/projects/{slug}/next
Signed in: an API token with the write scope, or the site's session.
Parameters
slugstringpathrequiredA project's short name
curl -X POST 'https://api.chassidushub.org/v1/projects/<slug>/next' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.claimNext({
slug: "<slug>"
});Try it
Let go of an item you held#
POSTPOST /v1/projects/{slug}/release
Signed in: an API token with the write scope, or the site's session.
Parameters
slugstringpathrequiredA project's short name
Body application/jsonrequired
{
"type": "object",
"properties": {
"item": {
"type": "string"
}
},
"required": [
"item"
]
}curl -X POST 'https://api.chassidushub.org/v1/projects/<slug>/release' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"item":"<item>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.releaseClaim({
slug: "<slug>",
body: {
item: "<item>"
}
});Try it
Close a project (its keepers, stewards)#
POSTPOST /v1/projects/{slug}/close
Signed in: an API token with the write scope, or the site's session.
Parameters
slugstringpathrequiredA project's short name
curl -X POST 'https://api.chassidushub.org/v1/projects/<slug>/close' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.closeProject({
slug: "<slug>"
});Try it
Personal#
What you follow, where you stopped
- GET
/v1/followsWhat you follow, the items themselves, and what changed in them lately - POST
/v1/followsFollow or unfollow an item, set, project, suggestion or issue - GET
/v1/placesWhere you stopped reading and listening lately (never cached) - PUT
/v1/placesKeep where you stopped in one thing - DELETE
/v1/placesForget one place
What you follow, the items themselves, and what changed in them lately#
GETGET /v1/follows
Signed in: an API token (read scope is enough), or the site's session.
Parameters
limitintegerqueryHow many (at most 100)
curl 'https://api.chassidushub.org/v1/follows' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.listFollows();Try it
Follow or unfollow an item, set, project, suggestion or issue#
POSTPOST /v1/follows
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"kind": {
"enum": [
"entity",
"set",
"project",
"changeset",
"report"
]
},
"id": {
"type": "string"
},
"on": {
"type": "boolean",
"description": "false to unfollow"
}
},
"required": [
"kind",
"id"
]
}curl -X POST 'https://api.chassidushub.org/v1/follows' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"kind":"entity","id":"<id>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.follow({
body: {
kind: "entity",
id: "<id>"
}
});Try it
Where you stopped reading and listening lately (never cached)#
GETGET /v1/places
Signed in: an API token (read scope is enough), or the site's session.
Parameters
kindread | listenquerykeystringqueryOne thing only
limitintegerqueryHow many (at most 60)
curl 'https://api.chassidushub.org/v1/places' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.listPlaces();Try it
Keep where you stopped in one thing#
PUTPUT /v1/places
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"kind": {
"enum": [
"read",
"listen"
]
},
"key": {
"type": "string"
},
"title": {
"type": "string"
},
"sub": {
"type": "string"
},
"href": {
"type": "string"
},
"place": {
"type": "object",
"additionalProperties": true
}
},
"required": [
"kind",
"key",
"title",
"href",
"place"
]
}curl -X PUT 'https://api.chassidushub.org/v1/places' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"kind":"read","key":"<key>","title":"Fix the date","href":"<href>","place":{}}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.savePlace({
body: {
kind: "read",
key: "<key>",
title: "Fix the date",
href: "<href>",
place: {}
}
});Try it
Forget one place#
DELETEDELETE /v1/places
Signed in: an API token with the write scope, or the site's session.
Parameters
kindread | listenqueryrequiredkeystringqueryrequiredThe thing
curl -X DELETE 'https://api.chassidushub.org/v1/places?kind=read&key=%3Ckey%3E' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.forgetPlace({
kind: "read",
key: "<key>"
});Try it
Webhooks#
Every merge posted to your address, signed
- GET
/v1/webhooksYour webhooks: addresses every merge is posted to - POST
/v1/webhooksAdd a webhook (up to five); its signing secret is shown this once - DELETE
/v1/webhooks/{id}Remove a webhook
Your webhooks: addresses every merge is posted to#
GETGET /v1/webhooks
Signed in: an API token (read scope is enough), or the site's session.
curl 'https://api.chassidushub.org/v1/webhooks' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.listWebhooks();Try it
Add a webhook (up to five); its signing secret is shown this once#
POSTPOST /v1/webhooks
Signed in: an API token with the write scope, or the site's session.
Body application/jsonrequired
{
"type": "object",
"properties": {
"url": {
"type": "string",
"description": "https://…",
"format": "uri"
}
},
"required": [
"url"
]
}curl -X POST 'https://api.chassidushub.org/v1/webhooks' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"url":"<url>"}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.createWebhook({
body: {
url: "<url>"
}
});Try it
Remove a webhook#
DELETEDELETE /v1/webhooks/{id}
Signed in: an API token with the write scope, or the site's session.
Parameters
idintegerpathrequiredThe webhook
curl -X DELETE 'https://api.chassidushub.org/v1/webhooks/1' \
-H "Authorization: Bearer $CHASSIDUSHUB_TOKEN"import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub({ token: process.env.CHASSIDUSHUB_TOKEN });
const answer = await rh.deleteWebhook({
id: 1
});Try it
Tokens#
Personal API tokens, made on the account page, and apps connected with OAuth
- GET
/v1/tokensYour API tokens (their prefixes only), revoked ones marked - POST
/v1/tokensMake an API token; the token itself is shown this once - DELETE
/v1/tokens/{id}Revoke a token, or end a connected app; it stops working at once
Your API tokens (their prefixes only), revoked ones marked#
GETGET /v1/tokens
Only from the site's own pages, signed in; an API token cannot do this.
curl 'https://api.chassidushub.org/v1/tokens'Make an API token; the token itself is shown this once#
POSTPOST /v1/tokens
Only from the site's own pages, signed in; an API token cannot do this.
Body application/jsonrequired
{
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "What uses it",
"minLength": 1,
"maxLength": 80
},
"scopes": {
"type": "array",
"items": {
"enum": [
"read",
"write"
]
},
"description": "Default: read"
},
"expiresInDays": {
"type": "integer",
"minimum": 1,
"maximum": 3650
}
},
"required": [
"name"
]
}curl -X POST 'https://api.chassidushub.org/v1/tokens' \
-H 'Content-Type: application/json' \
-d '{"name":"<name>"}'Revoke a token, or end a connected app; it stops working at once#
DELETEDELETE /v1/tokens/{id}
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
idstringpathrequiredtok-… for a token, oac-… for a connected app
curl -X DELETE 'https://api.chassidushub.org/v1/tokens/<id>'OAuth#
Connecting an app (Claude, other MCP clients) as a person: OAuth 2.1 with PKCE, registration and metadata
- GET
/.well-known/oauth-protected-resourceThe API's Protected Resource Metadata (RFC 9728): which authorization server gives its tokens - GET
/.well-known/oauth-protected-resource/mcpThe MCP server's Protected Resource Metadata (RFC 9728), named in its 401's WWW-Authenticate - GET
/.well-known/oauth-authorization-serverAuthorization Server Metadata (RFC 8414): the endpoints, scopes read and write, PKCE S256, registration and Client ID Metadata Documents - POST
/oauth/registerRegister an app (RFC 7591): its name and redirect addresses; a secret only if it asks for one - GET
/oauth/authorizeStart connecting (authorization code with PKCE): the person is sent to the site's consent page, then back to the app - POST
/oauth/tokenTrade a code (with its PKCE verifier) or a refresh token for an access token (an hour) and a new refresh token - POST
/oauth/revokeRevoke an access or refresh token (RFC 7009): the whole connection ends - GET
/v1/oauth/requests/{id}An app's request to connect, for the consent page: the app, where it sends the person back, the scopes - POST
/v1/oauth/requests/{id}The person's answer to an app's request to connect; answers where to send the browser
The API's Protected Resource Metadata (RFC 9728): which authorization server gives its tokens#
GETGET /.well-known/oauth-protected-resource
curl 'https://api.chassidushub.org/.well-known/oauth-protected-resource'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.protectedResource();Try it
The MCP server's Protected Resource Metadata (RFC 9728), named in its 401's WWW-Authenticate#
GETGET /.well-known/oauth-protected-resource/mcp
curl 'https://api.chassidushub.org/.well-known/oauth-protected-resource/mcp'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.mcpProtectedResource();Try it
Register an app (RFC 7591): its name and redirect addresses; a secret only if it asks for one#
POSTPOST /oauth/register
Body application/jsonrequired
{
"type": "object",
"properties": {
"client_name": {
"type": "string"
},
"client_uri": {
"type": "string"
},
"redirect_uris": {
"type": "array",
"items": {
"type": "string"
},
"description": "https, http://localhost, or an app's own scheme"
},
"token_endpoint_auth_method": {
"enum": [
"none",
"client_secret_post",
"client_secret_basic"
]
},
"grant_types": {
"type": "array",
"items": {
"type": "string"
}
},
"response_types": {
"type": "array",
"items": {
"type": "string"
}
}
},
"required": [
"redirect_uris"
]
}curl -X POST 'https://api.chassidushub.org/oauth/register' \
-H 'Content-Type: application/json' \
-d '{"redirect_uris":["<redirect_uris>"]}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.oauthRegister({
body: {
redirect_uris: [
"<redirect_uris>"
]
}
});Try it
Start connecting (authorization code with PKCE): the person is sent to the site's consent page, then back to the app#
GETGET /oauth/authorize
Parameters
response_typecodequeryrequiredclient_idstringqueryrequiredA registered client_id, or the https address of the app's Client ID Metadata Document
redirect_uristringqueryscopestringqueryread, write or both, space separated (default both; the person may allow reading only)
statestringquerycode_challengestringqueryrequiredbase64url sha256 of the verifier
code_challenge_methodS256queryrequiredresourcestringqueryRFC 8707: https://api.chassidushub.org/mcp (the MCP server) or https://api.chassidushub.org (the whole API)
ui_localesstringqueryhe for the consent page in Hebrew (English otherwise)
curl 'https://api.chassidushub.org/oauth/authorize?response_type=code&client_id=%3Cclient_id%3E&code_challenge=%3Ccode_challenge%3E&code_challenge_method=S256'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.oauthAuthorize({
response_type: "code",
client_id: "<client_id>",
code_challenge: "<code_challenge>",
code_challenge_method: "S256"
});Try it
Trade a code (with its PKCE verifier) or a refresh token for an access token (an hour) and a new refresh token#
POSTPOST /oauth/token
Body application/x-www-form-urlencodedrequired
{
"type": "string",
"format": "binary"
}curl -X POST 'https://api.chassidushub.org/oauth/token' \
-H 'Content-Type: application/x-www-form-urlencoded' --data-binary @fileimport { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.oauthToken({
body: file,
contentType: "application/pdf"
});Revoke an access or refresh token (RFC 7009): the whole connection ends#
POSTPOST /oauth/revoke
Body application/x-www-form-urlencodedrequired
{
"type": "string",
"format": "binary"
}curl -X POST 'https://api.chassidushub.org/oauth/revoke' \
-H 'Content-Type: application/x-www-form-urlencoded' --data-binary @fileimport { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.oauthRevoke({
body: file,
contentType: "application/pdf"
});An app's request to connect, for the consent page: the app, where it sends the person back, the scopes#
GETGET /v1/oauth/requests/{id}
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
idstringpathrequired
curl 'https://api.chassidushub.org/v1/oauth/requests/<id>'The person's answer to an app's request to connect; answers where to send the browser#
POSTPOST /v1/oauth/requests/{id}
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
idstringpathrequired
Body application/jsonrequired
{
"type": "object",
"properties": {
"approve": {
"type": "boolean"
},
"scopes": {
"type": "array",
"items": {
"enum": [
"read",
"write"
]
},
"description": "Allowed; never more than asked"
}
},
"required": [
"approve"
]
}curl -X POST 'https://api.chassidushub.org/v1/oauth/requests/<id>' \
-H 'Content-Type: application/json' \
-d '{"approve":true}'Mirrors#
Editions and their signed dumps
- GET
/v1/mirrorsEverything a mirror needs: the git mirror, the release keys, every edition and its dumps - GET
/v1/editionsCatalog editions (dated snapshots) and their dumps, each with its size, sha256 and address - GET
/v1/editions/{tag}/manifest.jsonAn edition's signed manifest (Ed25519), exactly as signed - GET
/v1/editions/{tag}/SHA256SUMSAn edition's checksums, for sha256sum -c - GET
/dumps/{tag}/{name}One of an edition's dumps (SQLite, JSON Lines, Parquet)
Everything a mirror needs: the git mirror, the release keys, every edition and its dumps#
GETGET /v1/mirrors
curl 'https://api.chassidushub.org/v1/mirrors'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.mirrors();Try it
Catalog editions (dated snapshots) and their dumps, each with its size, sha256 and address#
GETGET /v1/editions
curl 'https://api.chassidushub.org/v1/editions'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.editions();Try it
An edition's signed manifest (Ed25519), exactly as signed#
GETGET /v1/editions/{tag}/manifest.json
Parameters
tagstringpathrequired
curl 'https://api.chassidushub.org/v1/editions/2026.40/manifest.json'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.editionManifest({
tag: "2026.40"
});Try it
An edition's checksums, for sha256sum -c#
GETGET /v1/editions/{tag}/SHA256SUMS
Parameters
tagstringpathrequired
curl 'https://api.chassidushub.org/v1/editions/<tag>/SHA256SUMS'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.editionChecksums({
tag: "<tag>"
});Try it
One of an edition's dumps (SQLite, JSON Lines, Parquet)#
GETGET /dumps/{tag}/{name}
Parameters
tagstringpathrequirednamestringpathrequired
curl 'https://api.chassidushub.org/dumps/<tag>/<name>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.getDump({
tag: "<tag>",
name: "<name>"
});Try it
Apps#
The Sichos Kodesh apps' catalog, at the paths and in the shapes they read
- GET
/v1/app/{schema}/catalog/manifest.jsonThe Sichos Kodesh apps' catalog manifest: the served release's version, size, sha256 and address - GET
/v1/app/{schema}/catalog/changelog.jsonThe apps' catalog changelog alone - GET
/v1/app/{schema}/catalog/latest/catalog.jsonRedirects to the served release's catalog.json - GET
/v1/app/{schema}/catalog/{version}/catalog.jsonThe apps' catalog: the farbrengens by year (v1), with the library (v2) and the works (v3) - GET
/v1/app/v3/texts/{sha256}A text of a sefer, where the apps look for it (the same as /v1/texts/{sha256}) - GET
/v1/app/itemThe item an app's fix or report link is about, by the app's own ids - GET
/v1/app/v1/app/android/latest.jsonThe phone app's newest release: redirects to the reader's packs Worker - GET
/v1/app/v1/app/android/download/{abi}The phone app's APK: redirects to the reader's packs Worker
The Sichos Kodesh apps' catalog manifest: the served release's version, size, sha256 and address#
GETGET /v1/app/{schema}/catalog/manifest.json
The same fields as Sichos-Kodesh's own catalog API (its `CatalogManifest`). The version is `2.<commit>.0`; a release missing a part the app needs (listed in `missing`) is numbered `0.<commit>.0`, so no app takes it.
Parameters
schemav1 | v2 | v3pathrequiredThe catalog schema: v1 the farbrengens (the web app), v2 with the library, v3 with the works (the phone)
curl 'https://api.chassidushub.org/v1/app/v1/catalog/manifest.json'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.appCatalogManifest({
schema: "v1"
});Try it
The apps' catalog changelog alone#
GETGET /v1/app/{schema}/catalog/changelog.json
Parameters
schemav1 | v2 | v3pathrequiredThe catalog schema: v1 the farbrengens (the web app), v2 with the library, v3 with the works (the phone)
curl 'https://api.chassidushub.org/v1/app/v1/catalog/changelog.json'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.appCatalogChangelog({
schema: "v1"
});Try it
Redirects to the served release's catalog.json#
GETGET /v1/app/{schema}/catalog/latest/catalog.json
Parameters
schemav1 | v2 | v3pathrequiredThe catalog schema: v1 the farbrengens (the web app), v2 with the library, v3 with the works (the phone)
curl 'https://api.chassidushub.org/v1/app/v1/catalog/latest/catalog.json'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.appCatalogLatest({
schema: "v1"
});Try it
The apps' catalog: the farbrengens by year (v1), with the library (v2) and the works (v3)#
GETGET /v1/app/{schema}/catalog/{version}/catalog.json
Byte for byte what the manifest's sha256 describes (also the ETag). Only the served version is found.
Parameters
schemav1 | v2 | v3pathrequiredThe catalog schema: v1 the farbrengens (the web app), v2 with the library, v3 with the works (the phone)
versionstringpathrequiredThe version the manifest names
curl 'https://api.chassidushub.org/v1/app/v1/catalog/<version>/catalog.json'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.appCatalogRelease({
schema: "v1",
version: "<version>"
});Try it
A text of a sefer, where the apps look for it (the same as /v1/texts/{sha256})#
GETGET /v1/app/v3/texts/{sha256}
Parameters
sha256stringpathrequiredA file, named by its sha256
curl 'https://api.chassidushub.org/v1/app/v3/texts/<sha256>'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.appSourceText({
sha256: "<sha256>"
});Try it
The item an app's fix or report link is about, by the app's own ids#
GETGET /v1/app/item
A farbrengen by `farbrengen` (its mafteiach number), a sefer by `work`, a page of it by `work` and `unit`; a page not found gives its sefer.
Parameters
farbrengenstringqueryworkstringqueryunitstringquery
curl 'https://api.chassidushub.org/v1/app/item'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.appItem();Try it
The phone app's newest release: redirects to the reader's packs Worker#
GETGET /v1/app/v1/app/android/latest.json
curl 'https://api.chassidushub.org/v1/app/v1/app/android/latest.json'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.appAndroidLatest();Try it
The phone app's APK: redirects to the reader's packs Worker#
GETGET /v1/app/v1/app/android/download/{abi}
Parameters
abiarm64-v8a | armeabi-v7a | universalpathrequired
curl 'https://api.chassidushub.org/v1/app/v1/app/android/download/arm64-v8a'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.appAndroidDownload({
abi: "arm64-v8a"
});Try it
Libraries#
OAI-PMH and IIIF
- GET
/manifests/iiif/{file}A served scan as a IIIF Presentation 3 manifest, for any IIIF viewer - GET
/oaiOAI-PMH 2.0 for libraries (oai_dc records), when switched on - POST
/oaiOAI-PMH, the same arguments sent as a form
A served scan as a IIIF Presentation 3 manifest, for any IIIF viewer#
GETGET /manifests/iiif/{file}
Parameters
filestringpathrequiredThe scan's id and .json
curl 'https://api.chassidushub.org/manifests/iiif/rh-7k2m9q4d'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.iiifManifest({
file: "rh-7k2m9q4d"
});Try it
OAI-PMH 2.0 for libraries (oai_dc records), when switched on#
GETGET /oai
Parameters
verbIdentify | ListMetadataFormats | ListSets | ListIdentifiers | ListRecords | GetRecordqueryrequiredmetadataPrefixstringqueryidentifierstringqueryfromstringqueryuntilstringquerysetstringqueryresumptionTokenstringquery
curl 'https://api.chassidushub.org/oai?verb=Identify'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.oai({
verb: "Identify"
});Try it
OAI-PMH, the same arguments sent as a form#
POSTPOST /oai
Body application/x-www-form-urlencodedrequired
{
"type": "string",
"format": "binary"
}curl -X POST 'https://api.chassidushub.org/oai' \
-H 'Content-Type: application/x-www-form-urlencoded' --data-binary @fileimport { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.oaiPost({
body: file,
contentType: "application/pdf"
});Agents#
llms.txt and the MCP server
- GET
/llms.txtA short guide for AI agents (llms.txt) - GET
/robots.txtWhat crawlers may read on the API: the guides and the files, not the routes - POST
/mcpThe Model Context Protocol server (Streamable HTTP, JSON answers, no sessions) - GET
/mcpNot offered: this server opens no event stream - DELETE
/mcpNot offered: there are no sessions to end
A short guide for AI agents (llms.txt)#
GETGET /llms.txt
curl 'https://api.chassidushub.org/llms.txt'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.llmsTxt();Try it
What crawlers may read on the API: the guides and the files, not the routes#
GETGET /robots.txt
curl 'https://api.chassidushub.org/robots.txt'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.robotsTxt();Try it
The Model Context Protocol server (Streamable HTTP, JSON answers, no sessions)#
POSTPOST /mcp
Tools: search, get_item, list_children, get_text, suggest_fix, list_issues, open_issue. Send JSON-RPC 2.0. Reading needs no account. A writing tool without a token answers 401 with WWW-Authenticate naming the Protected Resource Metadata (so MCP clients such as claude.ai ask the person to connect with OAuth), and with a read-only token 403 insufficient_scope. See docs/developers/agents.md. No account needed; signed in, a little more.
Body application/json
{
"type": "object",
"additionalProperties": true,
"description": "A JSON-RPC 2.0 message, or a batch"
}curl -X POST 'https://api.chassidushub.org/mcp' \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.mcp({
body: {}
});Try it
Not offered: this server opens no event stream#
GETGET /mcp
curl 'https://api.chassidushub.org/mcp'Try it
Not offered: there are no sessions to end#
DELETEDELETE /mcp
curl -X DELETE 'https://api.chassidushub.org/mcp'Try it
Sign-in#
The site's own sign-in; listed for completeness, not for other clients
- GET
/v1/auth/meWho is signed in, with their passkeys, Google accounts, emails and notifications - POST
/v1/auth/passkey/register/optionsA new account: the options for making a passkey - POST
/v1/auth/passkey/register/verifyA new account: the passkey made, checked; signs in - POST
/v1/auth/passkey/add/optionsAnother passkey for this account: its options - POST
/v1/auth/passkey/add/verifyAnother passkey for this account, checked and kept - GET
/v1/auth/usernameWhether a handle can be had, and a free one suggested from a name - POST
/v1/auth/usernameChoose a new handle; the old one keeps leading to you (never with a token) - POST
/v1/auth/nameChange the name you go by - POST
/v1/auth/passkey/sign-in/optionsSigning in with a passkey: its options - POST
/v1/auth/passkey/sign-in/verifySigning in with a passkey: checked; signs in - GET
/v1/auth/google/startSigning in with Google: off to Google - GET
/v1/auth/google/callbackSigning in with Google: back from Google - POST
/v1/auth/email/startSigning in by email: send a link - POST
/v1/auth/email/checkSigning in by email: what a link is for, before using it - POST
/v1/auth/email/verifySigning in by email: use the link; signs in - POST
/v1/auth/notificationsEmail about what you follow: off, a daily digest, or at once - POST
/v1/auth/email/unsubscribeStop email updates, from the link in any of them (no sign-in) - POST
/v1/auth/sign-outSign out this browser
Who is signed in, with their passkeys, Google accounts, emails and notifications#
GETGET /v1/auth/me
Only from the site's own pages, signed in; an API token cannot do this.
curl 'https://api.chassidushub.org/v1/auth/me'A new account: the options for making a passkey#
POSTPOST /v1/auth/passkey/register/options
Only from the site's own pages, signed in; an API token cannot do this.
Body application/jsonrequired
{
"type": "object",
"properties": {
"name": {
"type": "string"
},
"username": {
"type": "string",
"description": "A handle; else one is made from the name"
}
},
"required": [
"name"
]
}curl -X POST 'https://api.chassidushub.org/v1/auth/passkey/register/options' \
-H 'Content-Type: application/json' \
-d '{"name":"<name>"}'A new account: the passkey made, checked; signs in#
POSTPOST /v1/auth/passkey/register/verify
Only from the site's own pages, signed in; an API token cannot do this.
Body application/json
{
"type": "object",
"additionalProperties": true
}curl -X POST 'https://api.chassidushub.org/v1/auth/passkey/register/verify' \
-H 'Content-Type: application/json' \
-d '{}'Another passkey for this account: its options#
POSTPOST /v1/auth/passkey/add/options
Only from the site's own pages, signed in; an API token cannot do this.
curl -X POST 'https://api.chassidushub.org/v1/auth/passkey/add/options'Another passkey for this account, checked and kept#
POSTPOST /v1/auth/passkey/add/verify
Only from the site's own pages, signed in; an API token cannot do this.
Body application/json
{
"type": "object",
"additionalProperties": true
}curl -X POST 'https://api.chassidushub.org/v1/auth/passkey/add/verify' \
-H 'Content-Type: application/json' \
-d '{}'Whether a handle can be had, and a free one suggested from a name#
GETGET /v1/auth/username
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
namestringqueryThe handle wanted
fromstringqueryA name to suggest one from
curl 'https://api.chassidushub.org/v1/auth/username'Choose a new handle; the old one keeps leading to you (never with a token)#
POSTPOST /v1/auth/username
Only from the site's own pages, signed in; an API token cannot do this.
Body application/jsonrequired
{
"type": "object",
"properties": {
"username": {
"type": "string"
}
},
"required": [
"username"
]
}curl -X POST 'https://api.chassidushub.org/v1/auth/username' \
-H 'Content-Type: application/json' \
-d '{"username":"<username>"}'Change the name you go by#
POSTPOST /v1/auth/name
Only from the site's own pages, signed in; an API token cannot do this.
Body application/jsonrequired
{
"type": "object",
"properties": {
"name": {
"type": "string"
}
},
"required": [
"name"
]
}curl -X POST 'https://api.chassidushub.org/v1/auth/name' \
-H 'Content-Type: application/json' \
-d '{"name":"<name>"}'Signing in with a passkey: its options#
POSTPOST /v1/auth/passkey/sign-in/options
Only from the site's own pages, signed in; an API token cannot do this.
curl -X POST 'https://api.chassidushub.org/v1/auth/passkey/sign-in/options'Signing in with a passkey: checked; signs in#
POSTPOST /v1/auth/passkey/sign-in/verify
Only from the site's own pages, signed in; an API token cannot do this.
Body application/json
{
"type": "object",
"additionalProperties": true
}curl -X POST 'https://api.chassidushub.org/v1/auth/passkey/sign-in/verify' \
-H 'Content-Type: application/json' \
-d '{}'Signing in with Google: off to Google#
GETGET /v1/auth/google/start
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
returnstringqueryWhere on the site to come back to
curl 'https://api.chassidushub.org/v1/auth/google/start'Signing in with Google: back from Google#
GETGET /v1/auth/google/callback
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
statestringquerycodestringquery
curl 'https://api.chassidushub.org/v1/auth/google/callback'Signing in by email: send a link#
POSTPOST /v1/auth/email/start
Only from the site's own pages, signed in; an API token cannot do this.
Body application/jsonrequired
{
"type": "object",
"properties": {
"email": {
"type": "string"
},
"return": {
"type": "string"
},
"lang": {
"type": "string"
}
},
"required": [
"email"
]
}curl -X POST 'https://api.chassidushub.org/v1/auth/email/start' \
-H 'Content-Type: application/json' \
-d '{"email":"<email>"}'Signing in by email: what a link is for, before using it#
POSTPOST /v1/auth/email/check
Only from the site's own pages, signed in; an API token cannot do this.
Body application/jsonrequired
{
"type": "object",
"properties": {
"token": {
"type": "string"
}
},
"required": [
"token"
]
}curl -X POST 'https://api.chassidushub.org/v1/auth/email/check' \
-H 'Content-Type: application/json' \
-d '{"token":"<token>"}'Signing in by email: use the link; signs in#
POSTPOST /v1/auth/email/verify
Only from the site's own pages, signed in; an API token cannot do this.
Body application/jsonrequired
{
"type": "object",
"properties": {
"token": {
"type": "string"
},
"name": {
"type": "string"
},
"username": {
"type": "string",
"description": "For a new account: a handle"
}
},
"required": [
"token"
]
}curl -X POST 'https://api.chassidushub.org/v1/auth/email/verify' \
-H 'Content-Type: application/json' \
-d '{"token":"<token>"}'Email about what you follow: off, a daily digest, or at once#
POSTPOST /v1/auth/notifications
Only from the site's own pages, signed in; an API token cannot do this.
Body application/jsonrequired
{
"type": "object",
"properties": {
"mode": {
"enum": [
"off",
"daily",
"immediate"
]
},
"email": {
"type": "string"
},
"lang": {
"type": "string"
}
},
"required": [
"mode"
]
}curl -X POST 'https://api.chassidushub.org/v1/auth/notifications' \
-H 'Content-Type: application/json' \
-d '{"mode":"off"}'Stop email updates, from the link in any of them (no sign-in)#
POSTPOST /v1/auth/email/unsubscribe
Parameters
tokenstringquery
Body application/json
{
"type": "object",
"properties": {
"token": {
"type": "string"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/auth/email/unsubscribe' \
-H 'Content-Type: application/json' \
-d '{}'import { ChassidusHub } from '@chassidushub/client';
const rh = new ChassidusHub();
const answer = await rh.unsubscribe({
body: {}
});Try it
Sign out this browser#
POSTPOST /v1/auth/sign-out
Only from the site's own pages, signed in; an API token cannot do this.
curl -X POST 'https://api.chassidushub.org/v1/auth/sign-out'Stewards#
The stewards' tools on the site; listed for completeness
- GET
/v1/admin/peopleEveryone with an account (stewards) - POST
/v1/admin/people/{id}/roleAppoint or remove a steward or admin (admins) - POST
/v1/admin/people/{id}/suspendSuspend or restore an account (its API tokens are revoked) - GET
/v1/admin/takedownsTakedown requests, with the files each points at - POST
/v1/admin/files/{sha256}/takedownTake a file down: kept privately, no longer served
Everyone with an account (stewards)#
GETGET /v1/admin/people
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
qstringqueryA name or id
curl 'https://api.chassidushub.org/v1/admin/people'Appoint or remove a steward or admin (admins)#
POSTPOST /v1/admin/people/{id}/role
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
idstringpathrequired
Body application/json
{
"type": "object",
"properties": {
"steward": {
"type": "boolean"
},
"admin": {
"type": "boolean"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/admin/people/<id>/role' \
-H 'Content-Type: application/json' \
-d '{}'Suspend or restore an account (its API tokens are revoked)#
POSTPOST /v1/admin/people/{id}/suspend
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
idstringpathrequired
Body application/json
{
"type": "object",
"properties": {
"on": {
"type": "boolean"
},
"reason": {
"type": "string"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/admin/people/<id>/suspend' \
-H 'Content-Type: application/json' \
-d '{}'Takedown requests, with the files each points at#
GETGET /v1/admin/takedowns
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
statusopen | resolved | dismissedquery
curl 'https://api.chassidushub.org/v1/admin/takedowns'Take a file down: kept privately, no longer served#
POSTPOST /v1/admin/files/{sha256}/takedown
Only from the site's own pages, signed in; an API token cannot do this.
Parameters
sha256stringpathrequiredA file, named by its sha256
Body application/json
{
"type": "object",
"properties": {
"report": {
"type": "integer"
}
}
}curl -X POST 'https://api.chassidushub.org/v1/admin/files/<sha256>/takedown' \
-H 'Content-Type: application/json' \
-d '{}'