DevelopersUsing the API
API reference
RebbeHub API 1.0.0: 173 routes in 23 groups, read from the API's own OpenAPI document.
https://api.rebbehub.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/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.rebbehub.org/'Try it
About this API: its version, the latest commit, where the docs are#
GETGET /v1
curl 'https://api.rebbehub.org/v1'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.about();Try it
This document#
GETGET /openapi.json
curl 'https://api.rebbehub.org/openapi.json'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.openapi();Try it
How many items of each type, and the latest commit#
GETGET /v1/stats
curl 'https://api.rebbehub.org/v1/stats'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/community'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.community();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.rebbehub.org/v1/health'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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/{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}/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/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.rebbehub.org/v1/types'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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
afterstringqueryDeprecated: the same as cursor
limitintegerqueryHow many (at most 500)
cursorstringqueryThe `next` of the page before
curl 'https://api.rebbehub.org/v1/entities'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/entities/batch?ids=%3Cids%3E'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/entities/rh-7k2m9q4d'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/entities/rh-7k2m9q4d/children?field=%3Cfield%3E&type=%3Ctype%3E'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/entities/rh-7k2m9q4d/linked/counts'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.linkedCounts({
id: "rh-7k2m9q4d"
});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…)
typestringqueryOnly items of this type
afterstringqueryDeprecated: the same as cursor
limitintegerqueryHow many (at most 500)
cursorstringqueryThe `next` of the page before
curl 'https://api.rebbehub.org/v1/entities/rh-7k2m9q4d/linked?field=%3Cfield%3E'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
for await (const item of rh.all('listLinked', {
id: "rh-7k2m9q4d",
field: "<field>"
})) {
console.log(item);
}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.rebbehub.org/v1/entities/rh-7k2m9q4d/history'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/entities/rh-7k2m9q4d/backlinks'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/entities/rh-7k2m9q4d/relations'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/revisions/1'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/resolve?path=%2Fevents%2F5742-05-10'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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
limitintegerqueryHow many (at most 2000)
curl 'https://api.rebbehub.org/v1/events'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/refcounts?field=%3Cfield%3E'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/sitemap'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/sitemap/set/1'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/works/rh-7k2m9q4d/outline'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/works/rh-7k2m9q4d/parts/<part>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.workPart({
id: "rh-7k2m9q4d",
part: "<part>"
});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)
cursorstringqueryThe `next` of the page before
curl 'https://api.rebbehub.org/v1/commits'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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/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.rebbehub.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 { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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
limitintegerqueryHow many (at most 100)
curl 'https://api.rebbehub.org/v1/search?q=%D7%99%D7%95%22%D7%93%20%D7%A9%D7%91%D7%98'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.search({
q: "יו\"ד שבט"
});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.rebbehub.org/v1/search/moments?q=%D7%99%D7%95%22%D7%93%20%D7%A9%D7%91%D7%98'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/search/similar?q=%D7%99%D7%95%22%D7%93%20%D7%A9%D7%91%D7%98'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.searchSimilar({
q: "יו\"ד שבט"
});Try it
Texts#
Scans' texts line by line, printings compared, translations
- 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)
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.rebbehub.org/v1/scans/rh-7k2m9q4d/text'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/scans/rh-7k2m9q4d/progress'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/scans/rh-7k2m9q4d/text/fix' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"page":1,"line":"<line>","text":"<text>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/scans/rh-7k2m9q4d/text/confirm' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"page":1}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/scans/rh-7k2m9q4d/ocr' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"content":"<content>","engine":{"name":"<name>","version":"<version>"}}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/scans/rh-7k2m9q4d/text/seed' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"layer":"rh-7k2m9q4d"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/units/rh-7k2m9q4d/printings'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/compare?a=%3Ca%3E&b=%3Cb%3E'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/units/rh-7k2m9q4d/translations' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"language":"<language>","credit":"<credit>","content":"<content>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/translations/fix' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"segment":"rh-7k2m9q4d","content":"<content>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/hanachos/text' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"content":"<content>","rights":"mine"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/texts/<sha256>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.getSourceText({
sha256: "<sha256>"
});Try it
Media#
Transcripts and their sync
- GET
/v1/recordings/{id}/transcriptA recording's transcript, with its sync by paragraph and word - 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/{id}/hanachaThe hanacha synced to this recording, paragraph by paragraph
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.rebbehub.org/v1/recordings/rh-7k2m9q4d/transcript'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.recordingTranscript({
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"
}
},
"required": [
"segment",
"content"
]
}curl -X POST 'https://api.rebbehub.org/v1/recordings/rh-7k2m9q4d/transcript/fix' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"segment":"rh-7k2m9q4d","content":"<content>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/recordings/rh-7k2m9q4d/sync/anchor' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"segment":"rh-7k2m9q4d","atMs":1}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/recordings/rh-7k2m9q4d/sync/confirm' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_TOKEN });
const answer = await rh.confirmSync({
id: "rh-7k2m9q4d"
});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.rebbehub.org/v1/recordings/rh-7k2m9q4d/hanacha'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.recordingHanacha({
id: "rh-7k2m9q4d"
});Try it
Files#
File bytes (while their rights allow), page images, uploads
- 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
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.rebbehub.org/v1/files/<sha256>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/files/<sha256>/similar'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/page-fixes/drive/<id>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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 RebbeHub passes on (300 MB) answer 413.
Parameters
idstringpathrequiredA Google Drive file id
curl 'https://api.rebbehub.org/v1/drive/<id>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/objects/<sha256>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/manifests/<collection>/<name>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/scans/rh-7k2m9q4d/pages'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/uploads?what=recording&rights=mine' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/pdf' --data-binary @fileimport { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/uploads/check' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"for":"rh-7k2m9q4d"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/uploads/propose' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"what":"hanacha"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/files/<sha256>/about'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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 RebbeHub only links to is served; the PDF is not (its file page links to the source).
Parameters
idsstringqueryThe sefarim
curl 'https://api.rebbehub.org/v1/covers'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/works/rh-7k2m9q4d/cover'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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`) - 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}/revertUndo a merged suggestion (a new suggestion that reverses it) - POST
/v1/suggestions/wordsA page's words fixed segment by segment: one segment's new words, a segment added after it or taken out, or a page's first words, sent for review - 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.rebbehub.org/v1/entities/rh-7k2m9q4d/restore' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"rev":1}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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
postReviewtrue | falsequerytrue: live changes waiting to be reviewed after
limitintegerqueryHow many (at most 500)
cursorstringqueryThe `next` of the page before
curl 'https://api.rebbehub.org/v1/suggestions'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/suggestions' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"title":"Fix the date"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/quick' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"entityId":"rh-7k2m9q4d","data":{}}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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`)#
GETGET /v1/suggestions/{id}
No account needed; signed in, a little more.
Parameters
idintegerpathrequiredThe suggestion
curl 'https://api.rebbehub.org/v1/suggestions/1'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/suggestions/1' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/1/conversation'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/suggestions/1/comments' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"<body>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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"
}
},
"required": [
"verdict"
]
}curl -X POST 'https://api.rebbehub.org/v1/suggestions/1/reviews' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"verdict":"approve"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/1/review-requests' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"reviewers":["<reviewers>"]}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/1/review-requests/<username>' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/1/items' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"type":"<type>","data":{}}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/1/submit' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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"
},
"note": {
"type": "string"
}
}
}curl -X POST 'https://api.rebbehub.org/v1/suggestions/1/approve' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/1/send-back' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/1/review-live' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"verdict":"approve"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/suggestions/1/withdraw' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_TOKEN });
const answer = await rh.withdrawSuggestion({
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.rebbehub.org/v1/suggestions/1/revert' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_TOKEN });
const answer = await rh.revertSuggestion({
id: 1,
body: {}
});Try it
A page's words fixed segment by segment: one segment's new words, a segment added after it or taken out, or a page's first words, 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"
]
},
"version": {
"type": "string"
},
"segment": {
"type": "string"
},
"text": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": true
},
"description": "Runs: { text, marks?, href? }, { note }, { marker }, { br: true }"
},
"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.rebbehub.org/v1/suggestions/words' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"entityId":"rh-7k2m9q4d","change":"edit"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_TOKEN });
const answer = await rh.suggestWords({
body: {
entityId: "rh-7k2m9q4d",
change: "edit"
}
});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.rebbehub.org/v1/suggestions/contents-map' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"publication":"rh-7k2m9q4d","pages":{"from":1,"to":1}}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/comments/1/resolve' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/tree'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/organize/preview' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"operations":[{"op":null}]}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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. 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.rebbehub.org/v1/organize' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"operations":[{"op":null}]}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/entities/rh-7k2m9q4d/talk'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/entities/rh-7k2m9q4d/talk' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"<body>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/comments/1/hide' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/comments/1' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"<body>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/reports' \
-H 'Content-Type: application/json' \
-d '{"reason":"wrong-fact"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/reports' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/reports/1/close' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"outcome":"resolved"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/takedowns' \
-H 'Content-Type: application/json' \
-d '{"target":"<target>","name":"<name>","email":"<email>","relation":"rights-holder","statement":"<statement>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/teshuros/rh-7k2m9q4d/family-request' \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/issues'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/issues' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"title":"Fix the date"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/issues/templates'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/issues/1'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/issues/1' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/issues/1/state' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"state":"open"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/issues/1/labels' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"labels":["<labels>"]}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/issues/1/assignees' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"assignees":["<assignees>"]}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/issues/1/visibility' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"private":true}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/issues/1/comments' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"body":"<body>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/labels'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/labels' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"name":"<name>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/people'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/people/<username>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/threads'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/threads/1'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/inbox' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/inbox/count' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/inbox/read' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/missing?kind=recordings'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/projects'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/projects' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"slug":"<slug>","name":"<name>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/projects/<slug>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/projects/<slug>/next' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/projects/<slug>/release' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"item":"<item>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/projects/<slug>/close' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/follows' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/follows' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"kind":"entity","id":"<id>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/places' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/places' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"kind":"read","key":"<key>","title":"Fix the date","href":"<href>","place":{}}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/places?kind=read&key=%3Ckey%3E' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/webhooks' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/webhooks' \
-H "Authorization: Bearer $REBBEHUB_TOKEN" \
-H 'Content-Type: application/json' \
-d '{"url":"<url>"}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.org/v1/webhooks/1' \
-H "Authorization: Bearer $REBBEHUB_TOKEN"import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub({ token: process.env.REBBEHUB_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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.org/.well-known/oauth-protected-resource'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/.well-known/oauth-protected-resource/mcp'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/oauth/register' \
-H 'Content-Type: application/json' \
-d '{"redirect_uris":["<redirect_uris>"]}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/mcp (the MCP server) or https://api.rebbehub.org (the whole API)
ui_localesstringqueryen for the consent page in English
curl 'https://api.rebbehub.org/oauth/authorize?response_type=code&client_id=%3Cclient_id%3E&code_challenge=%3Ccode_challenge%3E&code_challenge_method=S256'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/oauth/token' \
-H 'Content-Type: application/x-www-form-urlencoded' --data-binary @fileimport { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/oauth/revoke' \
-H 'Content-Type: application/x-www-form-urlencoded' --data-binary @fileimport { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.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.rebbehub.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.rebbehub.org/v1/mirrors'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/editions'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/editions/2026.40/manifest.json'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/v1/editions/<tag>/SHA256SUMS'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/dumps/<tag>/<name>'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.getDump({
tag: "<tag>",
name: "<name>"
});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.rebbehub.org/manifests/iiif/rh-7k2m9q4d'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/oai?verb=Identify'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.org/oai' \
-H 'Content-Type: application/x-www-form-urlencoded' --data-binary @fileimport { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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) - 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.rebbehub.org/llms.txt'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.llmsTxt();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.rebbehub.org/mcp' \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
const answer = await rh.mcp({
body: {}
});Try it
Not offered: this server opens no event stream#
GETGET /mcp
curl 'https://api.rebbehub.org/mcp'Try it
Not offered: there are no sessions to end#
DELETEDELETE /mcp
curl -X DELETE 'https://api.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.org/v1/auth/email/unsubscribe' \
-H 'Content-Type: application/json' \
-d '{}'import { RebbeHub } from '@rebbehub/client';
const rh = new RebbeHub();
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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.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.rebbehub.org/v1/admin/files/<sha256>/takedown' \
-H 'Content-Type: application/json' \
-d '{}'