{"success":true,"data":{"service":"Ekoli Yeden Digital Home API","tagline":"Preserving Our Past. Celebrating Our Present. Building Our Future.","version":"1.0.0","environment":"production","documentation":"/docs/architecture.md","endpoints":[{"method":"POST","path":"/api/auth/register","description":"Create a contributor account"},{"method":"POST","path":"/api/auth/login","description":"Sign in and receive an access token"},{"method":"POST","path":"/api/auth/refresh","description":"Exchange a refresh token for a new session"},{"method":"POST","path":"/api/auth/logout","description":"End the current session"},{"method":"GET","path":"/api/auth/me","description":"The signed-in user, their roles and their permissions"},{"method":"POST","path":"/api/auth/forgot-password","description":"Request a password reset link"},{"method":"GET","path":"/api/auth/reset-password/:token","description":"Check whether a reset link is still valid"},{"method":"POST","path":"/api/auth/reset-password","description":"Set a new password using a reset link"},{"method":"GET","path":"/api/contribute/types","description":"What may be contributed, and what happens next"},{"method":"POST","path":"/api/contribute","description":"Submit material to the archive for review"},{"method":"POST","path":"/api/contribute/media","description":"Attach a photograph, document or recording to a contribution"},{"method":"GET","path":"/api/contribute/upload-config","description":"What may be uploaded, the size limits, and the usage permissions offered"},{"method":"POST","path":"/api/contribute/upload","description":"Upload a file for the Preservation Team to review"},{"method":"GET","path":"/api/contribute/news/form","description":"The categories the news form offers"},{"method":"POST","path":"/api/contribute/news","description":"Send news in for an administrator to consider publishing"},{"method":"GET","path":"/api/contribute/news/:reference","description":"What happened to news you sent in"},{"method":"GET","path":"/api/contribute/person/form","description":"The categories and consent bases the profile builder offers"},{"method":"POST","path":"/api/contribute/person","description":"Send a profile of somebody from Ekoli-Yeden for review"},{"method":"GET","path":"/api/contribute/person/:reference","description":"What happened to a profile you sent in"},{"method":"GET","path":"/api/contribute/word/form","description":"The parts of speech, categories and variant kinds the word form offers"},{"method":"POST","path":"/api/contribute/word","description":"Propose a dictionary entry — the word, its meanings and a sentence using it"},{"method":"GET","path":"/api/contribute/word/:reference","description":"Check the progress of a proposed dictionary entry"},{"method":"GET","path":"/api/contribute/status/:reference","description":"Check the progress of a contribution using its reference code"},{"method":"GET","path":"/api/editorial/dashboard","description":"Draft, pending, published and rejected counts for the Editorial Team"},{"method":"GET","path":"/api/editorial/strings","description":"All editable website text, grouped, with drafts"},{"method":"PUT","path":"/api/editorial/strings/:key","description":"Save a draft change to a piece of website text"},{"method":"POST","path":"/api/editorial/strings/:key/submit","description":"Submit a text draft for review"},{"method":"POST","path":"/api/editorial/strings/:key/review","description":"Approve or reject a submitted text change"},{"method":"POST","path":"/api/editorial/strings/:key/publish","description":"Publish an approved text change to the live website"},{"method":"GET","path":"/api/editorial/hero","description":"The five homepage hero slides, including unpublished ones"},{"method":"PUT","path":"/api/editorial/hero/:slide","description":"Edit one hero slide"},{"method":"GET","path":"/api/editorial/navigation","description":"Navigation menus"},{"method":"PATCH","path":"/api/editorial/navigation/:id","description":"Edit a navigation label, destination or order"},{"method":"GET","path":"/api/editorial/sources","description":"The citation library"},{"method":"POST","path":"/api/editorial/sources","description":"Record a new source"},{"method":"POST","path":"/api/editorial/sources/attach","description":"Cite a source on a record"},{"method":"GET","path":"/api/editorial/versions/:resourceType/:resourceId","description":"The edit history of one record"},{"method":"GET","path":"/api/editorial/versions/:resourceType/:resourceId/:version","description":"One earlier version of a record, in full"},{"method":"GET","path":"/api/admin/dashboard","description":"Counts per content type and status, and the moderation queue"},{"method":"GET","path":"/api/admin/settings","description":"All site settings, grouped"},{"method":"PUT","path":"/api/admin/settings","description":"Update site setting values"},{"method":"GET","path":"/api/admin/media","description":"Browse the R2 media library"},{"method":"POST","path":"/api/admin/media","description":"Upload a file to R2 and record it in D1"},{"method":"PATCH","path":"/api/admin/media/:id","description":"Catalogue a media item — title, credit, location, date taken"},{"method":"DELETE","path":"/api/admin/media/:id","description":"Delete a media item from R2 and D1"},{"method":"GET","path":"/api/admin/festival-galleries","description":"Every festival with its photograph album and a count of what is in it"},{"method":"POST","path":"/api/admin/festivals/:id/gallery","description":"A festival's album, created if it does not exist yet"},{"method":"POST","path":"/api/admin/festivals/:id/years","description":"Add a year to a festival"},{"method":"POST","path":"/api/admin/festivals","description":"Create a festival edition, together with its photograph album"},{"method":"PATCH","path":"/api/admin/festivals/:id/status","description":"Move a festival through the editorial workflow, taking its album with it"},{"method":"GET","path":"/api/admin/galleries/:id/items","description":"Every photograph in an album, in any status"},{"method":"POST","path":"/api/admin/galleries/:id/items","description":"Upload a photograph straight into an album"},{"method":"POST","path":"/api/admin/galleries/:id/items/existing","description":"File a photograph already in the media library into an album"},{"method":"PATCH","path":"/api/admin/gallery-items/:id","description":"Label a photograph — who is in it, where, when, who took it"},{"method":"DELETE","path":"/api/admin/gallery-items/:id","description":"Take a photograph out of an album. The file itself is kept"},{"method":"GET","path":"/api/admin/submissions","description":"The community contribution queue"},{"method":"GET","path":"/api/admin/submissions/:id","description":"One contribution in full"},{"method":"PATCH","path":"/api/admin/submissions/:id/review","description":"Approve, reject or archive a contribution"},{"method":"GET","path":"/api/admin/language/gaps","description":"Entries with no meaning, no recording or no example — the work still to do"},{"method":"GET","path":"/api/admin/language/:id/entry","description":"One dictionary entry in full, drafts included"},{"method":"PUT","path":"/api/admin/language/:id/entry","description":"Save an entry's senses, variants and example sentences"},{"method":"POST","path":"/api/admin/language","description":"Add a dictionary entry"},{"method":"PUT","path":"/api/admin/language/:id","description":"Update a dictionary entry"},{"method":"PATCH","path":"/api/admin/language/:id","description":"Partially update a dictionary entry"},{"method":"GET","path":"/api/admin/word-submissions","description":"Dictionary entries proposed by the community, awaiting a language editor"},{"method":"POST","path":"/api/admin/word-submissions/:id/promote","description":"Turn a proposed entry into a draft dictionary entry, crediting the contributor"},{"method":"POST","path":"/api/admin/word-submissions/:id/reject","description":"Decline a proposed entry. It is kept, not deleted"},{"method":"GET","path":"/api/admin/roles","description":"Platform roles and the Preservation Team structure"},{"method":"GET","path":"/api/admin/users","description":"List platform users"},{"method":"POST","path":"/api/admin/users","description":"Create an account for a team member"},{"method":"PATCH","path":"/api/admin/users/:id","description":"Update a user profile, status or Preservation Team position"},{"method":"POST","path":"/api/admin/users/:id/password","description":"Set another user password directly and end their sessions"},{"method":"POST","path":"/api/admin/users/:id/reset-link","description":"Generate a password reset link for a user, sending it where possible and returning it so an administrator can pass it on"},{"method":"POST","path":"/api/admin/users/:id/temporary-password","description":"Set a temporary password that must be replaced at next sign-in — for somebody who cannot open a reset link"},{"method":"POST","path":"/api/admin/users/:id/close","description":"Close an account: no sign-in, no sessions, out of the directory"},{"method":"POST","path":"/api/admin/events/:id/gallery","description":"Give an event its own album, so its photographs are filed under the occasion"},{"method":"GET","path":"/api/admin/news-submissions","description":"News sent in by members, awaiting an administrator"},{"method":"POST","path":"/api/admin/news-submissions/:id/promote","description":"Publish submitted news, optionally rewriting it first"},{"method":"POST","path":"/api/admin/news-submissions/:id/review","description":"Ask for more, or decline submitted news"},{"method":"GET","path":"/api/admin/person-submissions","description":"Profiles of people sent in by the community, awaiting review"},{"method":"POST","path":"/api/admin/person-submissions/:id/promote","description":"Publish a submitted profile. Refuses where consent is unsettled"},{"method":"POST","path":"/api/admin/person-submissions/:id/review","description":"Ask for more, reject, or mark a submitted profile a duplicate"},{"method":"GET","path":"/api/admin/contributions","description":"Files uploaded by the community, awaiting review"},{"method":"GET","path":"/api/admin/contributions/:id/file","description":"Stream a contributed file for review — never public"},{"method":"POST","path":"/api/admin/contributions/:id/approve","description":"Approve a contributed file and copy it into the archive"},{"method":"POST","path":"/api/admin/contributions/:id/reject","description":"Reject a contributed file. The file is retained, not deleted"},{"method":"POST","path":"/api/admin/users/:id/roles","description":"Grant a role to a user"},{"method":"DELETE","path":"/api/admin/users/:id/roles/:role","description":"Remove a role from a user"},{"method":"POST","path":"/api/admin/account/password","description":"Change your own password"},{"method":"GET","path":"/api/admin/audit-logs","description":"The audit trail"},{"method":"GET","path":"/api/admin/pages","description":"List all page records in every status"},{"method":"GET","path":"/api/admin/pages/:identifier","description":"Read one page in any status"},{"method":"POST","path":"/api/admin/pages","description":"Create a page"},{"method":"PUT","path":"/api/admin/pages/:id","description":"Update a page"},{"method":"PATCH","path":"/api/admin/pages/:id","description":"Partially update a page"},{"method":"PATCH","path":"/api/admin/pages/:id/status","description":"Move a page through the editorial workflow"},{"method":"DELETE","path":"/api/admin/pages/:id","description":"Delete a page"},{"method":"GET","path":"/api/admin/history","description":"List all history entry records in every status"},{"method":"GET","path":"/api/admin/history/:identifier","description":"Read one history entry in any status"},{"method":"POST","path":"/api/admin/history","description":"Create a history entry"},{"method":"PUT","path":"/api/admin/history/:id","description":"Update a history entry"},{"method":"PATCH","path":"/api/admin/history/:id","description":"Partially update a history entry"},{"method":"PATCH","path":"/api/admin/history/:id/status","description":"Move a history entry through the editorial workflow"},{"method":"DELETE","path":"/api/admin/history/:id","description":"Delete a history entry"},{"method":"GET","path":"/api/admin/leaders","description":"List all leader records in every status"},{"method":"GET","path":"/api/admin/leaders/:identifier","description":"Read one leader in any status"},{"method":"POST","path":"/api/admin/leaders","description":"Create a leader"},{"method":"PUT","path":"/api/admin/leaders/:id","description":"Update a leader"},{"method":"PATCH","path":"/api/admin/leaders/:id","description":"Partially update a leader"},{"method":"PATCH","path":"/api/admin/leaders/:id/status","description":"Move a leader through the editorial workflow"},{"method":"DELETE","path":"/api/admin/leaders/:id","description":"Delete a leader"},{"method":"GET","path":"/api/admin/people","description":"List all person records in every status"},{"method":"GET","path":"/api/admin/people/:identifier","description":"Read one person in any status"},{"method":"POST","path":"/api/admin/people","description":"Create a person"},{"method":"PUT","path":"/api/admin/people/:id","description":"Update a person"},{"method":"PATCH","path":"/api/admin/people/:id","description":"Partially update a person"},{"method":"PATCH","path":"/api/admin/people/:id/status","description":"Move a person through the editorial workflow"},{"method":"DELETE","path":"/api/admin/people/:id","description":"Delete a person"},{"method":"GET","path":"/api/admin/news","description":"List all news item records in every status"},{"method":"GET","path":"/api/admin/news/:identifier","description":"Read one news item in any status"},{"method":"POST","path":"/api/admin/news","description":"Create a news item"},{"method":"PUT","path":"/api/admin/news/:id","description":"Update a news item"},{"method":"PATCH","path":"/api/admin/news/:id","description":"Partially update a news item"},{"method":"PATCH","path":"/api/admin/news/:id/status","description":"Move a news item through the editorial workflow"},{"method":"DELETE","path":"/api/admin/news/:id","description":"Delete a news item"},{"method":"GET","path":"/api/admin/events","description":"List all event records in every status"},{"method":"GET","path":"/api/admin/events/:identifier","description":"Read one event in any status"},{"method":"POST","path":"/api/admin/events","description":"Create a event"},{"method":"PUT","path":"/api/admin/events/:id","description":"Update a event"},{"method":"PATCH","path":"/api/admin/events/:id","description":"Partially update a event"},{"method":"PATCH","path":"/api/admin/events/:id/status","description":"Move a event through the editorial workflow"},{"method":"DELETE","path":"/api/admin/events/:id","description":"Delete a event"},{"method":"GET","path":"/api/admin/festivals","description":"List all festival records in every status"},{"method":"GET","path":"/api/admin/festivals/:identifier","description":"Read one festival in any status"},{"method":"POST","path":"/api/admin/festivals","description":"Create a festival"},{"method":"PUT","path":"/api/admin/festivals/:id","description":"Update a festival"},{"method":"PATCH","path":"/api/admin/festivals/:id","description":"Partially update a festival"},{"method":"PATCH","path":"/api/admin/festivals/:id/status","description":"Move a festival through the editorial workflow"},{"method":"DELETE","path":"/api/admin/festivals/:id","description":"Delete a festival"},{"method":"GET","path":"/api/admin/language-categories","description":"List all language category records in every status"},{"method":"GET","path":"/api/admin/language-categories/:identifier","description":"Read one language category in any status"},{"method":"POST","path":"/api/admin/language-categories","description":"Create a language category"},{"method":"PUT","path":"/api/admin/language-categories/:id","description":"Update a language category"},{"method":"PATCH","path":"/api/admin/language-categories/:id","description":"Partially update a language category"},{"method":"PATCH","path":"/api/admin/language-categories/:id/status","description":"Move a language category through the editorial workflow"},{"method":"DELETE","path":"/api/admin/language-categories/:id","description":"Delete a language category"},{"method":"GET","path":"/api/admin/language","description":"List all ekoli word records in every status"},{"method":"GET","path":"/api/admin/language/:identifier","description":"Read one ekoli word in any status"},{"method":"POST","path":"/api/admin/language","description":"Create a ekoli word"},{"method":"PUT","path":"/api/admin/language/:id","description":"Update a ekoli word"},{"method":"PATCH","path":"/api/admin/language/:id","description":"Partially update a ekoli word"},{"method":"PATCH","path":"/api/admin/language/:id/status","description":"Move a ekoli word through the editorial workflow"},{"method":"DELETE","path":"/api/admin/language/:id","description":"Delete a ekoli word"},{"method":"GET","path":"/api/admin/galleries","description":"List all gallery records in every status"},{"method":"GET","path":"/api/admin/galleries/:identifier","description":"Read one gallery in any status"},{"method":"POST","path":"/api/admin/galleries","description":"Create a gallery"},{"method":"PUT","path":"/api/admin/galleries/:id","description":"Update a gallery"},{"method":"PATCH","path":"/api/admin/galleries/:id","description":"Partially update a gallery"},{"method":"PATCH","path":"/api/admin/galleries/:id/status","description":"Move a gallery through the editorial workflow"},{"method":"DELETE","path":"/api/admin/galleries/:id","description":"Delete a gallery"},{"method":"GET","path":"/api/admin/stories","description":"List all story records in every status"},{"method":"GET","path":"/api/admin/stories/:identifier","description":"Read one story in any status"},{"method":"POST","path":"/api/admin/stories","description":"Create a story"},{"method":"PUT","path":"/api/admin/stories/:id","description":"Update a story"},{"method":"PATCH","path":"/api/admin/stories/:id","description":"Partially update a story"},{"method":"PATCH","path":"/api/admin/stories/:id/status","description":"Move a story through the editorial workflow"},{"method":"DELETE","path":"/api/admin/stories/:id","description":"Delete a story"},{"method":"GET","path":"/api/admin/recordings","description":"List all recording records in every status"},{"method":"GET","path":"/api/admin/recordings/:identifier","description":"Read one recording in any status"},{"method":"POST","path":"/api/admin/recordings","description":"Create a recording"},{"method":"PUT","path":"/api/admin/recordings/:id","description":"Update a recording"},{"method":"PATCH","path":"/api/admin/recordings/:id","description":"Partially update a recording"},{"method":"PATCH","path":"/api/admin/recordings/:id/status","description":"Move a recording through the editorial workflow"},{"method":"DELETE","path":"/api/admin/recordings/:id","description":"Delete a recording"},{"method":"GET","path":"/api/admin/quizzes","description":"List all quiz records in every status"},{"method":"GET","path":"/api/admin/quizzes/:identifier","description":"Read one quiz in any status"},{"method":"POST","path":"/api/admin/quizzes","description":"Create a quiz"},{"method":"PUT","path":"/api/admin/quizzes/:id","description":"Update a quiz"},{"method":"PATCH","path":"/api/admin/quizzes/:id","description":"Partially update a quiz"},{"method":"PATCH","path":"/api/admin/quizzes/:id/status","description":"Move a quiz through the editorial workflow"},{"method":"DELETE","path":"/api/admin/quizzes/:id","description":"Delete a quiz"},{"method":"GET","path":"/api/admin/videos","description":"List all video records in every status"},{"method":"GET","path":"/api/admin/videos/:identifier","description":"Read one video in any status"},{"method":"POST","path":"/api/admin/videos","description":"Create a video"},{"method":"PUT","path":"/api/admin/videos/:id","description":"Update a video"},{"method":"PATCH","path":"/api/admin/videos/:id","description":"Partially update a video"},{"method":"PATCH","path":"/api/admin/videos/:id/status","description":"Move a video through the editorial workflow"},{"method":"DELETE","path":"/api/admin/videos/:id","description":"Delete a video"},{"method":"GET","path":"/api/admin/businesses","description":"List all business records in every status"},{"method":"GET","path":"/api/admin/businesses/:identifier","description":"Read one business in any status"},{"method":"POST","path":"/api/admin/businesses","description":"Create a business"},{"method":"PUT","path":"/api/admin/businesses/:id","description":"Update a business"},{"method":"PATCH","path":"/api/admin/businesses/:id","description":"Partially update a business"},{"method":"PATCH","path":"/api/admin/businesses/:id/status","description":"Move a business through the editorial workflow"},{"method":"DELETE","path":"/api/admin/businesses/:id","description":"Delete a business"},{"method":"GET","path":"/api/admin/organizations","description":"List all organization records in every status"},{"method":"GET","path":"/api/admin/organizations/:identifier","description":"Read one organization in any status"},{"method":"POST","path":"/api/admin/organizations","description":"Create a organization"},{"method":"PUT","path":"/api/admin/organizations/:id","description":"Update a organization"},{"method":"PATCH","path":"/api/admin/organizations/:id","description":"Partially update a organization"},{"method":"PATCH","path":"/api/admin/organizations/:id/status","description":"Move a organization through the editorial workflow"},{"method":"DELETE","path":"/api/admin/organizations/:id","description":"Delete a organization"},{"method":"GET","path":"/api/admin/culture","description":"List all culture article records in every status"},{"method":"GET","path":"/api/admin/culture/:identifier","description":"Read one culture article in any status"},{"method":"POST","path":"/api/admin/culture","description":"Create a culture article"},{"method":"PUT","path":"/api/admin/culture/:id","description":"Update a culture article"},{"method":"PATCH","path":"/api/admin/culture/:id","description":"Partially update a culture article"},{"method":"PATCH","path":"/api/admin/culture/:id/status","description":"Move a culture article through the editorial workflow"},{"method":"DELETE","path":"/api/admin/culture/:id","description":"Delete a culture article"},{"method":"GET","path":"/api/admin/age-grades","description":"List all age grade records in every status"},{"method":"GET","path":"/api/admin/age-grades/:identifier","description":"Read one age grade in any status"},{"method":"POST","path":"/api/admin/age-grades","description":"Create a age grade"},{"method":"PUT","path":"/api/admin/age-grades/:id","description":"Update a age grade"},{"method":"PATCH","path":"/api/admin/age-grades/:id","description":"Partially update a age grade"},{"method":"PATCH","path":"/api/admin/age-grades/:id/status","description":"Move a age grade through the editorial workflow"},{"method":"DELETE","path":"/api/admin/age-grades/:id","description":"Delete a age grade"},{"method":"GET","path":"/api/admin/cultural-groups","description":"List all cultural group records in every status"},{"method":"GET","path":"/api/admin/cultural-groups/:identifier","description":"Read one cultural group in any status"},{"method":"POST","path":"/api/admin/cultural-groups","description":"Create a cultural group"},{"method":"PUT","path":"/api/admin/cultural-groups/:id","description":"Update a cultural group"},{"method":"PATCH","path":"/api/admin/cultural-groups/:id","description":"Partially update a cultural group"},{"method":"PATCH","path":"/api/admin/cultural-groups/:id/status","description":"Move a cultural group through the editorial workflow"},{"method":"DELETE","path":"/api/admin/cultural-groups/:id","description":"Delete a cultural group"},{"method":"GET","path":"/api/admin/music","description":"List all cultural music records in every status"},{"method":"GET","path":"/api/admin/music/:identifier","description":"Read one cultural music in any status"},{"method":"POST","path":"/api/admin/music","description":"Create a cultural music"},{"method":"PUT","path":"/api/admin/music/:id","description":"Update a cultural music"},{"method":"PATCH","path":"/api/admin/music/:id","description":"Partially update a cultural music"},{"method":"PATCH","path":"/api/admin/music/:id/status","description":"Move a cultural music through the editorial workflow"},{"method":"DELETE","path":"/api/admin/music/:id","description":"Delete a cultural music"},{"method":"GET","path":"/api/admin/community","description":"List all community project records in every status"},{"method":"GET","path":"/api/admin/community/:identifier","description":"Read one community project in any status"},{"method":"POST","path":"/api/admin/community","description":"Create a community project"},{"method":"PUT","path":"/api/admin/community/:id","description":"Update a community project"},{"method":"PATCH","path":"/api/admin/community/:id","description":"Partially update a community project"},{"method":"PATCH","path":"/api/admin/community/:id/status","description":"Move a community project through the editorial workflow"},{"method":"DELETE","path":"/api/admin/community/:id","description":"Delete a community project"},{"method":"GET","path":"/api/age-grades-activity","description":"The most recent posts across every published age grade"},{"method":"GET","path":"/api/my/age-grades","description":"The age grades you administer"},{"method":"POST","path":"/api/age-grades","description":"Register your age grade. You become its lead administrator"},{"method":"GET","path":"/api/age-grades/:identifier/manage","description":"Everything about a grade, drafts included, for its administrators"},{"method":"GET","path":"/api/age-grades/:identifier/posts","description":"An age grade's news, newest first"},{"method":"GET","path":"/api/age-grades/:identifier/posts/:postSlug","description":"One post by an age grade"},{"method":"GET","path":"/api/age-grades/:identifier","description":"One age grade with its posts, its roster and its photographs"},{"method":"PATCH","path":"/api/age-grades/:identifier","description":"Edit your age grade's own description"},{"method":"POST","path":"/api/age-grades/:identifier/posts","description":"Post news, a meeting notice or a report under your age grade"},{"method":"PATCH","path":"/api/age-grades/:identifier/posts/:postId","description":"Edit or take down one of your age grade posts"},{"method":"DELETE","path":"/api/age-grades/:identifier/posts/:postId","description":"Delete one of your age grade posts"},{"method":"POST","path":"/api/age-grades/:identifier/admins","description":"Appoint another administrator for your age grade. Lead administrators only"},{"method":"DELETE","path":"/api/age-grades/:identifier/admins/:userId","description":"Remove an administrator. The last lead cannot be removed"},{"method":"POST","path":"/api/age-grades/:identifier/members","description":"Add somebody to your age grade roster"},{"method":"PATCH","path":"/api/age-grades/:identifier/members/:memberId","description":"Update a member of your age grade roster"},{"method":"DELETE","path":"/api/age-grades/:identifier/members/:memberId","description":"Remove somebody from your age grade roster"},{"method":"GET","path":"/api/directory/facets","description":"The professions and countries that actually have members behind them"},{"method":"GET","path":"/api/directory","description":"Members who chose to be findable, by profession, skill and place"},{"method":"GET","path":"/api/membership/options","description":"Professions, skills, interests and the wording for every choice the joining form offers"},{"method":"GET","path":"/api/membership/skills","description":"The skill vocabulary, searchable, ordered by how many members hold each"},{"method":"POST","path":"/api/membership/join","description":"Turn this account into a Yakoli membership"},{"method":"GET","path":"/api/membership/dashboard","description":"The whole Okoli account in one request — profile, notifications, what is missing"},{"method":"GET","path":"/api/membership/me","description":"Your own profile, in full"},{"method":"PATCH","path":"/api/membership/me","description":"Save one stage of your profile. Everything is optional"},{"method":"POST","path":"/api/membership/me/photo","description":"Set your profile picture or cover image (?kind=avatar|cover)"},{"method":"DELETE","path":"/api/membership/me/photo","description":"Take your profile picture or cover image off your profile"},{"method":"PATCH","path":"/api/membership/me/privacy","description":"Change what other people can see, and whether you appear in the directory"},{"method":"PUT","path":"/api/membership/me/skills","description":"Replace your skills. A skill the list does not have is added to it"},{"method":"PUT","path":"/api/membership/me/interests","description":"Replace the areas of community life you are interested in"},{"method":"GET","path":"/api/notifications","description":"Your notifications, newest first"},{"method":"POST","path":"/api/notifications/read-all","description":"Mark every notification read"},{"method":"POST","path":"/api/notifications/:id/read","description":"Mark one notification read"},{"method":"GET","path":"/api/push/status","description":"Whether push is available, wanted, and which devices are registered"},{"method":"POST","path":"/api/push/subscribe","description":"Register this device for notifications"},{"method":"POST","path":"/api/push/unsubscribe","description":"Forget this device"},{"method":"PUT","path":"/api/push/preference","description":"Turn device notifications on or off everywhere at once"},{"method":"GET","path":"/api/admin/membership/statistics","description":"The community snapshot — counts by work situation, country and skill. Aggregates only"},{"method":"GET","path":"/api/members/:handle","description":"One member's profile, shaped to what you are allowed to see"},{"method":"GET","path":"/api/membership/family","description":"My family: confirmed connections, and the requests waiting on me"},{"method":"GET","path":"/api/membership/family/options","description":"The relationships the platform recognises, grouped for a picker"},{"method":"POST","path":"/api/membership/family/requests","description":"Ask somebody to confirm a family relationship, by member or by phone number"},{"method":"POST","path":"/api/membership/family/:id/accept","description":"Confirm a relationship, choosing what you are to them in return"},{"method":"POST","path":"/api/membership/family/:id/decline","description":"Decline a connection request"},{"method":"DELETE","path":"/api/membership/family/:id","description":"End a connection. Either side may, and it takes only one of them"},{"method":"GET","path":"/api/membership/birthdays/today","description":"Whose birthday it is among the people I know, and whether it is my own"},{"method":"DELETE","path":"/api/membership/birthdays/wishes/:id","description":"Hide a message left on my own birthday chart"},{"method":"POST","path":"/api/membership/birthdays/:userId/wish","description":"Wish a member a happy birthday. Kept in their chart for that year"},{"method":"POST","path":"/api/membership/birthdays/:userId/skip","description":"Not now. The card does not come back until next year"},{"method":"GET","path":"/api/membership/remembrance/notice","description":"What a reported or memorialised account is told when its holder signs in"},{"method":"POST","path":"/api/membership/remembrance/contest","description":"Contest a report about your own account. Restores it immediately"},{"method":"POST","path":"/api/membership/remembrance/reports","description":"Record that somebody has died. Changes nothing until family confirm it"},{"method":"POST","path":"/api/membership/remembrance/reports/:id/confirm","description":"Confirm a report. Requires a close relationship recorded before it was made"},{"method":"GET","path":"/api/admin/remembrance","description":"Death reports awaiting review"},{"method":"POST","path":"/api/admin/remembrance/:id/publish","description":"Publish the memorial page in the Ancestry Records"},{"method":"POST","path":"/api/admin/remembrance/:id/reject","description":"Reject a report and restore the account. Available at any stage"},{"method":"GET","path":"/api/members/:handle/birthdays","description":"One year of a member's birthday chart, and every year that has wishes in it"},{"method":"GET","path":"/api/groups/kinds","description":"The kinds of group the archive recognises, and how joining can work"},{"method":"POST","path":"/api/groups/members/:memberId/decide","description":"An officer answering a request to join"},{"method":"POST","path":"/api/groups/dues/:paymentId/settle","description":"The treasurer confirming a declared payment against the account"},{"method":"POST","path":"/api/groups/issues/:issueId/settle","description":"An officer answering something a member raised"},{"method":"GET","path":"/api/membership/groups/suggestions","description":"Which age grade is mine, and which groups I already belong to"},{"method":"GET","path":"/api/groups","description":"The community groups of Ekoli-Yeden"},{"method":"POST","path":"/api/groups","description":"Register a group. The person who registers it becomes its lead officer"},{"method":"GET","path":"/api/groups/:identifier","description":"One group: its page, its officers, its roster and where the viewer stands in it"},{"method":"PATCH","path":"/api/groups/:id","description":"A group's own officers editing its page and its dues"},{"method":"POST","path":"/api/groups/:id/join","description":"Ask to join, or join outright where the group allows it"},{"method":"GET","path":"/api/groups/:id/requests","description":"Who has asked to join, for the officers"},{"method":"POST","path":"/api/groups/:id/officers","description":"The lead officer appointing another"},{"method":"DELETE","path":"/api/groups/:id/officers/:userId","description":"Stand an officer down. The last lead officer cannot be removed"},{"method":"POST","path":"/api/groups/:id/accounts","description":"Where members should send the dues. Shown to members, never to the public"},{"method":"PATCH","path":"/api/groups/:id/accounts/:accountId","description":"Change the account details. Every change keeps what the value was before"},{"method":"GET","path":"/api/groups/:id/accounts/history","description":"Who changed the account details, when, and what they were before"},{"method":"GET","path":"/api/groups/:id/dues","description":"My payments, or every payment where I am an officer"},{"method":"POST","path":"/api/groups/:id/dues","description":"Record a payment made. No money passes through this website"},{"method":"GET","path":"/api/groups/:id/issues","description":"What I have raised, or everything where I am an officer"},{"method":"POST","path":"/api/groups/:id/issues","description":"Raise something with the officers of a group. Private by default"},{"method":"GET","path":"/api/opportunities/options","description":"The kinds, places and reporting reasons the board recognises"},{"method":"GET","path":"/api/opportunities","description":"The board, ordered by what you can do and how near it is"},{"method":"POST","path":"/api/opportunities","description":"Post a job, scholarship or training. Goes to review before anybody sees it"},{"method":"GET","path":"/api/opportunities/:identifier","description":"One listing, with which of its skills you already have"},{"method":"POST","path":"/api/opportunities/:id/save","description":"Keep a listing for later"},{"method":"DELETE","path":"/api/opportunities/:id/save","description":"Stop keeping a listing"},{"method":"POST","path":"/api/opportunities/:id/report","description":"Report a listing as fraudulent, misleading or closed"},{"method":"GET","path":"/api/admin/opportunities/reports","description":"Listings members have reported"},{"method":"POST","path":"/api/admin/opportunities/reports/:id/settle","description":"Uphold or dismiss a report"},{"method":"GET","path":"/api/admin/opportunities","description":"Listings awaiting review"},{"method":"PATCH","path":"/api/admin/opportunities/:id","description":"Publish, reject, verify or unflag a listing"},{"method":"POST","path":"/api/forums","description":"Start a forum"},{"method":"POST","path":"/api/forums/:space/members/invite","description":"Add somebody to a forum by handle"},{"method":"GET","path":"/api/forums/mine","description":"Every forum, and where you stand in each"},{"method":"POST","path":"/api/forums/:space/join","description":"Ask to join a forum"},{"method":"POST","path":"/api/forums/:space/leave","description":"Leave a forum. Not the General Forum"},{"method":"GET","path":"/api/forums/:space/members","description":"The roster and the queue, for a forum’s administrators"},{"method":"POST","path":"/api/forums/:space/members/:userId/decide","description":"Approve, reject, remove, suspend, restore or change a role"},{"method":"GET","path":"/api/forums/admin/reports","description":"Reported posts and topics, child-safety first"},{"method":"POST","path":"/api/forums/admin/reports/:id/settle","description":"Action or dismiss a report"},{"method":"POST","path":"/api/forums/admin/moderate","description":"Hide, remove, restore, lock or pin. Every action is recorded permanently"},{"method":"POST","path":"/api/forums/admin/sanctions","description":"Warn, suspend or ban a member from the forums"},{"method":"GET","path":"/api/forums/admin/actions","description":"The moderation log — append-only, and readable by every moderator"},{"method":"PATCH","path":"/api/forums/posts/:id","description":"Edit your own reply. The edit is stamped rather than silent"},{"method":"POST","path":"/api/forums/topics/:id/follow","description":"Be told when somebody replies to this conversation"},{"method":"POST","path":"/api/forums/:targetType/:id/react","description":"Add or remove a reaction. Counts are shown and order nothing"},{"method":"POST","path":"/api/forums/:targetType/:id/report","description":"Report a topic or reply. Child-safety reports hide it immediately"},{"method":"GET","path":"/api/forums","description":"The three spaces, and whether you may enter each"},{"method":"POST","path":"/api/forums/:space/topics","description":"Start a conversation"},{"method":"POST","path":"/api/forums/:space/topics/:topic/replies","description":"Reply to a conversation"},{"method":"GET","path":"/api/forums/:space/topics/:topic","description":"One conversation with its replies"},{"method":"GET","path":"/api/forums/:space","description":"One space with its categories and conversations"},{"method":"GET","path":"/api/ancestry","description":"Everybody the archive remembers, most recent first, the undated last"},{"method":"POST","path":"/api/ancestry/:identifier/tributes","description":"Leave a tribute on a memorial"},{"method":"GET","path":"/api/ancestry/:identifier","description":"One memorial, with the tributes left on it"},{"method":"GET","path":"/api/admin/places/candidates","description":"Names members have typed that are not yet places"},{"method":"POST","path":"/api/admin/places/candidates/:id/promote","description":"Make a typed name a real place, early or with its spelling corrected"},{"method":"POST","path":"/api/admin/places/candidates/:id/dismiss","description":"Set aside a name that is not a place"},{"method":"GET","path":"/api/places","description":"Every place, as a tree ordered for a picker"},{"method":"GET","path":"/api/places/:identifier","description":"One place, what is above it, and what is inside it"},{"method":"GET","path":"/api/contact/topics","description":"What the form offers, and what each topic means"},{"method":"POST","path":"/api/contact","description":"Write to the Preservation Team. No account needed"},{"method":"GET","path":"/api/contact/:reference","description":"What happened to a message, for whoever holds the reference"},{"method":"GET","path":"/api/admin/contact","description":"Messages from the public, privacy and takedown requests first"},{"method":"POST","path":"/api/admin/contact/:id/status","description":"Pick one up, answer it, close it, or set it aside"},{"method":"GET","path":"/api/messages/unread","description":"How many messages are waiting, for the badge"},{"method":"GET","path":"/api/messages/people","description":"Members you could write to, by name. Carries no contact details"},{"method":"POST","path":"/api/messages/conversations","description":"Open the conversation with somebody, or find the existing one"},{"method":"GET","path":"/api/messages/contact-requests","description":"Requests waiting on me, the ones I have made, and who holds my details"},{"method":"POST","path":"/api/messages/contact-requests","description":"Ask to see somebody’s phone number or email. They decide"},{"method":"POST","path":"/api/messages/contact-requests/:id/decide","description":"Answer a request for your details — yes, or no"},{"method":"DELETE","path":"/api/messages/contact-grants/:viewerId","description":"Take your details back from somebody you shared them with"},{"method":"POST","path":"/api/messages/:id/read","description":"Mark a conversation read"},{"method":"GET","path":"/api/messages/:id","description":"One conversation and its messages"},{"method":"POST","path":"/api/messages/:id","description":"Send a message"},{"method":"PATCH","path":"/api/messages/:id","description":"Archive, mute or block — on your own side only"},{"method":"GET","path":"/api/messages","description":"My conversations, newest activity first"},{"method":"POST","path":"/api/messages/:id/attachments","description":"Send a photograph, a PDF or a voice note"},{"method":"GET","path":"/api/messages/:id/attachments/:attachmentId","description":"The bytes of one attachment, to somebody in the conversation"},{"method":"POST","path":"/api/messages/:id/live-ticket","description":"A thirty-second ticket for opening a live connection"},{"method":"GET","path":"/api/messages/:id/live","description":"The live connection for one conversation"},{"method":"GET","path":"/api/news-portal/overview","description":"The front of the section in one request: announcements, featured, latest, film"},{"method":"GET","path":"/api/news-portal/categories","description":"The categories, managed by the Editorial Team"},{"method":"GET","path":"/api/news-portal/tags","description":"The tags in use, most used first"},{"method":"GET","path":"/api/news-portal","description":"Published stories, searchable and filterable. Never anything else"},{"method":"GET","path":"/api/news-portal/:identifier","description":"One published story with its photographs, film, sources and tags"},{"method":"GET","path":"/api/editorial/news-list","description":"Every story, whatever its state, with the counts for the tabs"},{"method":"POST","path":"/api/editorial/news-categories","description":"Create or edit a category without a deployment"},{"method":"POST","path":"/api/editorial/news/publish-due","description":"Publish everything whose scheduled moment has passed, by hand"},{"method":"POST","path":"/api/editorial/news","description":"Start a story. Always as a draft"},{"method":"POST","path":"/api/editorial/news/:id/state","description":"Submit, approve, request changes, publish, schedule, archive or reject"},{"method":"POST","path":"/api/editorial/news/:id/flags","description":"Feature a story, or mark it important with an expiry"},{"method":"POST","path":"/api/editorial/news/:id/media/order","description":"Reorder a story photograph gallery"},{"method":"POST","path":"/api/editorial/news/:id/media","description":"Attach a photograph from the media library, or a YouTube video"},{"method":"PATCH","path":"/api/editorial/news/:id/media/:mediaId","description":"Caption, credit and alt text for one photograph"},{"method":"DELETE","path":"/api/editorial/news/:id/media/:mediaId","description":"Take a photograph off this story. The file stays in the library"},{"method":"POST","path":"/api/editorial/news/:id/sources","description":"Record where the story came from"},{"method":"DELETE","path":"/api/editorial/news/:id/sources/:sourceId","description":"Remove a source"},{"method":"GET","path":"/api/editorial/news/:identifier","description":"One story to edit or preview, whatever its state"},{"method":"PATCH","path":"/api/editorial/news/:id","description":"Edit a story. Snapshots the previous version and keeps the contributor"},{"method":"GET","path":"/api/hall-of-fame","description":"The Hall of Fame, when the community has switched it on"},{"method":"GET","path":"/api/map/places","description":"Every published place, and which of them have a recorded position"},{"method":"GET","path":"/api/learn/quizzes/:identifier","description":"One published quiz with its questions, marked in the browser"},{"method":"POST","path":"/api/editorial/places/:id/coordinates","description":"Record or clear where a place actually is"},{"method":"GET","path":"/api/editorial/quizzes/:id/questions","description":"The question set as the composer needs it"},{"method":"PUT","path":"/api/editorial/quizzes/:id/questions","description":"Replace a quiz’s whole question set in one write"},{"method":"POST","path":"/api/ask","description":"Ask a question and get an answer drawn from the published archive"},{"method":"GET","path":"/api/admin/ai/gaps","description":"Questions the archive could not answer, most asked first"},{"method":"POST","path":"/api/admin/ai/reindex","description":"Rebuild the passage index now rather than waiting for the cron"},{"method":"POST","path":"/api/admin/ai/quizzes/:quizId/draft","description":"Draft quiz questions from passages not yet used"},{"method":"GET","path":"/api/admin/ai/quizzes/drafts","description":"Drafted questions waiting to be read, each beside its passage"},{"method":"POST","path":"/api/admin/ai/quizzes/questions/:questionId/decide","description":"Approve a drafted question, or discard it"},{"method":"GET","path":"/api/health","description":"Service health check"},{"method":"GET","path":"/api/health/ready","description":"Deep readiness check across D1, R2 and configuration"},{"method":"GET","path":"/api/settings","description":"Public site settings used to render the website"},{"method":"GET","path":"/api/cms/bundle","description":"All published website text, hero slides and navigation, in one request"},{"method":"GET","path":"/api/cms/hero","description":"The five homepage hero slides with their images resolved"},{"method":"GET","path":"/api/sources/:resourceType/:resourceId","description":"The sources and references cited by one record"},{"method":"GET","path":"/api/contributors/:resourceType/:resourceId","description":"Contributor acknowledgement for one record"},{"method":"GET","path":"/api/search","description":"Search the whole archive"},{"method":"GET","path":"/api/community/overview","description":"Members, groups, counts and a feed of what has happened lately"},{"method":"GET","path":"/api/search/sources","description":"What the archive search covers"},{"method":"GET","path":"/api/language/index","description":"The A–Z index with counts, the parts of speech and entry types to filter by, and how much of the language is recorded so far"},{"method":"GET","path":"/api/language/categories","description":"Ekoli language categories"},{"method":"GET","path":"/api/language/categories/:slug","description":"One language category and its words"},{"method":"GET","path":"/api/language","description":"Ekoli language entries"},{"method":"GET","path":"/api/language/:identifier","description":"One Ekoli language entry with its pronunciation recordings"},{"method":"GET","path":"/api/festivals","description":"All published festivals, with the featured edition separated out"},{"method":"GET","path":"/api/festivals/:identifier","description":"One festival with its events, gallery and videos"},{"method":"GET","path":"/api/leboku","description":"The Leboku festival series, year by year"},{"method":"GET","path":"/api/leboku/:year","description":"One Leboku edition, e.g. /api/leboku/2026"},{"method":"GET","path":"/api/photographs","description":"Every published photograph in the archive, newest first, whichever album it belongs to"},{"method":"GET","path":"/api/events/calendar","description":"Everything happening — events and festivals together — split into upcoming and past"},{"method":"GET","path":"/api/galleries/albums/index","description":"Every published album with a count of what it holds, for the gallery filter bar"},{"method":"GET","path":"/api/galleries/:identifier","description":"One album with its photographs and their labels"},{"method":"GET","path":"/api/media/config","description":"Accepted media folders, types and size limits"},{"method":"GET","path":"/api/media/file/*","description":"Stream a file from R2 by storage key"},{"method":"GET","path":"/api/preservation-team","description":"Structure of the Ekoli-Yeden Preservation Team"},{"method":"GET","path":"/api/pages","description":"List published page records"},{"method":"GET","path":"/api/pages/:identifier","description":"Read one published page by slug or id"},{"method":"GET","path":"/api/history","description":"List published history entry records"},{"method":"GET","path":"/api/history/:identifier","description":"Read one published history entry by slug or id"},{"method":"GET","path":"/api/culture","description":"List published culture article records"},{"method":"GET","path":"/api/culture/:identifier","description":"Read one published culture article by slug or id"},{"method":"GET","path":"/api/age-grades","description":"List published age grade records"},{"method":"GET","path":"/api/age-grades/:identifier","description":"Read one published age grade by slug or id"},{"method":"GET","path":"/api/cultural-groups","description":"List published cultural group records"},{"method":"GET","path":"/api/cultural-groups/:identifier","description":"Read one published cultural group by slug or id"},{"method":"GET","path":"/api/music","description":"List published cultural music records"},{"method":"GET","path":"/api/music/:identifier","description":"Read one published cultural music by slug or id"},{"method":"GET","path":"/api/leaders","description":"List published leader records"},{"method":"GET","path":"/api/leaders/:identifier","description":"Read one published leader by slug or id"},{"method":"GET","path":"/api/people","description":"List published person records"},{"method":"GET","path":"/api/people/:identifier","description":"Read one published person by slug or id"},{"method":"GET","path":"/api/news","description":"List published news item records"},{"method":"GET","path":"/api/news/:identifier","description":"Read one published news item by slug or id"},{"method":"GET","path":"/api/events","description":"List published event records"},{"method":"GET","path":"/api/events/:identifier","description":"Read one published event by slug or id"},{"method":"GET","path":"/api/galleries","description":"List published gallery records"},{"method":"GET","path":"/api/galleries/:identifier","description":"Read one published gallery by slug or id"},{"method":"GET","path":"/api/videos","description":"List published video records"},{"method":"GET","path":"/api/videos/:identifier","description":"Read one published video by slug or id"},{"method":"GET","path":"/api/stories","description":"List published story records"},{"method":"GET","path":"/api/stories/:identifier","description":"Read one published story by slug or id"},{"method":"GET","path":"/api/recordings","description":"List published recording records"},{"method":"GET","path":"/api/recordings/:identifier","description":"Read one published recording by slug or id"},{"method":"GET","path":"/api/quizzes","description":"List published quiz records"},{"method":"GET","path":"/api/quizzes/:identifier","description":"Read one published quiz by slug or id"},{"method":"GET","path":"/api/businesses","description":"List published business records"},{"method":"GET","path":"/api/businesses/:identifier","description":"Read one published business by slug or id"},{"method":"GET","path":"/api/organizations","description":"List published organization records"},{"method":"GET","path":"/api/organizations/:identifier","description":"Read one published organization by slug or id"},{"method":"GET","path":"/api/community","description":"List published community project records"},{"method":"GET","path":"/api/community/:identifier","description":"Read one published community project by slug or id"}]}}