DevelopersUsing the API
The API for developers
A guide to the routes, by what they are for.
https://api.rebbehub.org serves the whole catalog, read without an account; /openapi.json lists every route. What changes the catalog needs a signed-in person: the site's session, or a personal API token made on /account (auth). The developer docs, with every route's examples and a reference to try them in, are at rebbehub.org/developers (developers/).
Reading#
GET /v1/entities/<id>,/v1/resolve?path=…,/v1/search?q=…,/v1/events?within=5742: items, by id, path, words or date.GET /v1/entities/<id>/history: every version, who made it and what changed.GET /v1/commits?since=<seq>: every merge afterseq, in order: the way to follow the catalog without webhooks.GET /v1/missing?kind=recordings|texts|scans,/v1/projects.GET /v1/scans/<id>/text?page=<n>,/v1/recordings/<id>/transcript: a scan's text and a recording's transcript, machine lines marked until people check them. A scan's page gives each line's proofread level (0, 1, 2) and the scan's text layers; a transcript gives each paragraph's sync, word by word where it has word timings, and whether a person locked or checked it.GET /v1/scans/<id>/progress: how far each page is proofread.GET /v1/recordings/<id>/hanacha: the farbrengen's hanacha, paragraph by paragraph with where each is heard in the recording.GET /v1/units/<id>/printings,/v1/compare?a=…&b=…: the printings of a sicha or letter whose text the catalog has (text:<id>, orscan:<id>:<from>-<to>for pages of a scan), and two of them compared word by word, the Hebrew way.GET /v1/projects/<slug>: a project, its progress and what is left; signed in,POST /v1/projects/<slug>/nexthands out the next item nobody holds.- Signed in:
POST /v1/scans/<id>/ocr(your own OCR: hOCR, ALTO, or plain text with form feeds between pages),/v1/scans/<id>/text/confirm("this page is right"),/v1/recordings/<id>/sync/anchor("the Rebbe is saying this line now", with the moment in milliseconds) and/v1/recordings/<id>/sync/confirm. Each is a suggestion, reviewed. GET /v1/files/<sha256>: a file's size, rights and address, what was made from it (a scan's reading copy) and its page fix.GET /v1/page-fixes/drive/<Drive id>: what a PDF on Google Drive needs to read straight - the pages to turn, each a PDF matrix (and, for a reading copy's placing, the box to cut to) - or the reading copy to open instead (operations)./objects/<sha256>: a file's bytes, while its rights let it be served./manifests/<name>/<name>.json: the published manifests of reading copies and page fixes.GET /v1/search/moments?q=…: where the words are inside the texts: a line on a scan's page (open/text/<scan>?page=<n>&line=<line>) or a paragraph of a text or transcript, withstartMs, when it is heard.machine: trueuntil a person has checked it.GET /v1/search/similar?q=…&types=unit,event: search by meaning.available: falseuntil it is set up; every result is the machine's choice, and says so (machine: true), with itsscore.GET /v1/entities/<id>/relations: an item's links both ways (cites, printed in, based on, cited by), eachmachine: truewhile a machine found it and no person has checked it.GET /v1/health: coverage per year and set, pages nobody has checked, recordings not synced, links that do not answer, the oldest open suggestions.GET /v1/mirrors,/v1/editions,/v1/editions/<tag>/manifest.json,/v1/editions/<tag>/SHA256SUMS,/dumps/<tag>/<name>: the git mirror, every catalog edition's dumps with their sha256, and the keys they are signed with (mirrors)./manifests/iiif/<scan>.json: a served scan as a IIIF Presentation 3 manifest (right to left, page images, the PDF as its rendering, the credit as its required statement), for any IIIF viewer.GET /v1/scans/<id>/pages: a scan's pages, with their page images and thumbnails.GET /v1/files/<sha256>/similar: other files that look like this one (the same pages, or the same recording), a machine guess.GET /v1/entities/<id>/linked/counts: everything that points at an item, by type and field, with how many of each.GET /v1/entities/<id>/linked?field=work&type=unit&after=…&limit=…: one of those groups in its own order (order key, date, part, page), up to 500 at a time, withtotalandnext(null at the end).GET /v1/covers?ids=rh-…,rh-…(up to 200): sefarim's covers, drawn from their title pages, while their PDFs are served or linked (a cover of a linked PDF is served; the PDF is not);machine: trueuntil a person chose the page.GET /v1/works/<id>/cover: one sefer's cover, the page chosen, and the PDFs it may be chosen from (linked: truefor one RebbeHub only links to).GET /v1/files/<sha256>/about: a file's own page: rights, where it came from, what was made from it and measured in it, the covers drawn from it, and the items that use it (usedBy.totaland the first of them).
OAI-PMH for libraries#
https://api.rebbehub.org/oai speaks OAI-PMH 2.0 (when switched on, deploy), Dublin Core records under CC0: see OAI-PMH and IIIF.
Translations#
A unit's translation is a text of its own (kind: translation) with its language, credit and licence (none: the translator's own, CC BY-SA). POST /v1/units/<id>/translations with { language, credit, licence?, translationOf?, content, machine? } sends one for review, a blank line between paragraphs; machine names the tool when a machine made it, and its paragraphs are marked so until a person checks each. POST /v1/translations/fix with { segment, content } suggests a fix to one paragraph. Only licences that let RebbeHub keep a copy are taken (public domain, CC0, CC BY, CC BY-NC); see rights.
Where you stopped#
GET /v1/places, PUT /v1/places, DELETE /v1/places?kind=&key=: where the signed-in person stopped reading (a PDF's page) and listening (a farbrengen's part and moment), the latest 60, so every device reopens there. Personal: never cached, never exported.
Adding#
With a signed-in session or a token with the write scope:
POST /v1/uploads/check({ sha256, pageHashes?, work?, publication? }): before an upload, whether RebbeHub has the file or one like it, and whether it looks like another scan of a printing, a new printing or a new teshura.POST /v1/uploadsalso takeswhat=hanacha(a PDF for a farbrengen or sicha,kind=mugah|bilti-mugah|…) andwhat=document(as=sefer,letterordocument, withtitle, andset,author,genre,year,unitas they apply); a recording or a hanacha may name a farbrengen the catalog lacks (eventTitle,eventDate) instead offor, and it is added with it.POST /v1/uploads/propose({ what, name, sha256? }): the machine's guess of where something new belongs, from the date and words in its name, and where the file already is.POST /v1/hanachos/text({ for | eventTitle+eventDate, content, rights, language?, credit? }): a hanacha's words, a paragraph to a segment, as a suggestion.POST /v1/suggestions/contents-map: Map pages, what pages of a publication hold, as a suggestion.POST /v1/suggestions/words({ entityId, change, version, segment, text, before?, kind?, language?, title?, note? }): a page's words fixed segment by segment (data model).changeisedit(the segment's newtext, as runs),add(a new segment after it),remove, orstart(a page's first words).beforeis the segment as the person saw it: if it has changed since, the answer is 409 and nothing is overwritten. Words are only runs with the fixed marks; anything else is refused or dropped.POST /v1/teshuros/<id>/family-request(no account, captcha as for reports): a family asks that a teshura stop being shown (rights).
People and conversations#
It works the way GitHub works. Suggestions are pull requests and Reports are issues, numbered together (#12 is one or the other, never both; GET /v1/threads/12 says which). Imports are not conversations and have no number. Reading needs no account (private issues aside); writing needs a signed-in session. People are named by their handle (accounts).
People
GET /v1/people?q=men&thread=changeset:<id>: people to @mention, those already in the conversation first.GET /v1/people/<handle>: a person's public page (an old handle finds them too, withmovedFrom).GET /v1/threads?q=: suggestions and issues to #mention, by number or words.
Suggestions
GET /v1/suggestions?state=open|closed|all&author=&reviewer=&q=: the list, with each one's number, reviewers, approvals, comments and the issues it closes, and the open and closed counts. Withoutstatethe older list (status=) answers as before.GET /v1/suggestions/<id>/conversation: the timeline in order (comments, reviews, and events: sent for review, review requested, renamed, referenced from elsewhere, merged, withdrawn, reverted), who is asked to review, and the issues it closes.POST /v1/suggestions/<id>/reviews:{ verdict: "approve" | "request_changes" | "comment", body?, comments?: [{ entity, field, body }] }, a whole review in one: Approve merges it (as/approvedoes), Request changes sends it back (as/send-backdoes), and the comments on fields are kept with the review.POST /v1/suggestions/<id>/comments:{ body, parent?, anchor?: { entity, field } }.POST /v1/suggestions/<id>/review-requests{ reviewers: [handle] }(asking someone who reviewed asks again),DELETE /v1/suggestions/<id>/review-requests/<handle>.PATCH /v1/suggestions/<id>{ title?, description? }.Fixes #12(orcloses,resolves,סוגר,מתקן…) in the description links issue 12; merging the suggestion closes it.
When a suggestion is sent for review, the keepers of the sets it touches are asked to review it on their own (as CODEOWNERS are), except for a bot's suggestions. When it comes back after changes were requested, those who requested them are asked again.
Issues
GET /v1/issues?state=&label=&type=&set=&entity=&assignee=&author=&q=: newest first, with the open and closed counts;assignee=nonefor those nobody has taken.GET /v1/issues/templates: the kinds of issue and the words each starts with.POST /v1/issues{ title, body?, type, entityId?, labels? }.GET /v1/issues/<number>: the issue, its timeline, the suggestions that close it, andrights: what the reader may do.PATCH /v1/issues/<number>{ title?, body? },POST …/state{ state: "open" | "completed" | "not_planned", note? },PUT …/labels{ labels },PUT …/assignees{ assignees },POST …/visibility{ private },POST …/comments{ body, parent? }.GET /v1/labels; stewards make them withPOST /v1/labels.
The suggestion list (with state), the issues and the inbox page like every list of the API: each answers next, passed back as cursor (before is still read). With a personal API token, the write scope opens issues, comments and reviews; handles are chosen on the site only (/v1/auth/username), never with a token.
Issues are public, as on GitHub, except those about rights or offensive content, which only stewards, the set's keepers, the reporter and those assigned may read. Every report sent before issues existed stays private. POST /v1/reports (no account) still works and now takes a title too; it answers with the new issue's number.
Comments and the inbox
PATCH /v1/comments/<id>{ body }(its writer);POST /v1/comments/<id>/resolve{ resolved }(a comment on a field).GET /v1/inbox?filter=unread|all|mention|review_requested|assigned|…,GET /v1/inbox/count,POST /v1/inbox/read{ ids? | subject?: { kind, id } | all?, unread? }.POST /v1/followstakes{ kind: "report", id }for an issue.
Webhooks#
On /account (For developers: webhooks), or POST /v1/webhooks with { "url": "https://…" }, a signed-in person registers up to five addresses; every merge from then on is posted to each, signed with the hook's secret. The body, the signature and retries: webhooks.
Embeds#
Every sefer, sicha, farbrengen and set can be shown on another site (Embed on another site, at the foot of its page):
<iframe src="https://rebbehub.org/embed/rh-…" width="100%" height="320" style="border:0" loading="lazy" title="RebbeHub"></iframe>A farbrengen's recordings play in place. /embed/… is the only page other sites may frame; every other page refuses (frame-ancestors 'self').