Deleting content
These endpoints remove resources that are already in your library. The reads that go with them are under Content. Renaming, editing, publishing, sharing and tagging stay under Managing content.
They need a token granted the content:delete scope, which is an OAuth path
today. It can be granted by an organization admin or a team admin. The person
behind the token must also be allowed to delete resources in Mereon, checked on
every call, so a demotion takes effect on the next one.
An organization admin deletes the resources. A team admin mostly removes them from the teams they administer, and the resources stay in the library for everyone else. A guide is deleted for the whole organization either way. Deleting can close lessons left with nothing to teach, and can stop people who are part-way through those lessons when you say so.
Which resources you can delete
Section titled “Which resources you can delete”A resource is named by the id GET /v1/content returns,
whatever its type: a video, an audio recording, a document or a guide. One call
names 1 to 25 of them. The same id is used on both routes below.
A resource you may delete proceeds, including an unpublished document that is
yours to delete. One you can see but may not delete is a 403. One you can
neither see nor delete is a 404. A set that mixes an id that does not exist
with one you may not delete answers 404 and names only the ids that do not
exist. When every id exists and some of them you may not delete, the call is
403 and deletes nothing.
Preview a deletion
Section titled “Preview a deletion”POST /v1/content/deletion-preview
Reports what deleting these resources would do, and changes nothing. Ask this
before POST /v1/content/deletions.
curl -X POST "https://api.mereon.ai/v1/content/deletion-preview" \ -H "Authorization: Bearer $MEREON_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "contentIds": ["cnt_…"] }'| Field | Type | Notes |
|---|---|---|
contentIds |
string[] | 1 to 25 ids from GET /v1/content. |
{ "scope": "organization", "deleting": [{ "contentId": "cnt_…", "title": "Returns policy" }], "unsharing": [], "blocked": [], "lessonsClosing": { "count": 1, "preview": [{ "id": "les_…", "title": "Returns" }] }, "lessonsStaying": { "count": 0, "preview": [] }, "learnersInProgress": 2, "inFlightAccessRequired": true, "orphanedTopics": { "topics": [{ "id": "top_…", "title": "Return window" }], "blocked": [], "content": [{ "contentId": "cnt_…", "title": "Returns policy" }], "lessonsClosing": { "count": 1, "preview": [{ "id": "les_…", "title": "Returns" }] }, "learnersInProgress": 1 }, "openIssues": { "count": 0, "spansOtherContent": false, "content": [] }}scope is organization or team. On organization, resources that can go
are listed under deleting and unsharing is empty. On team, most resources
are listed under unsharing and guides are listed under deleting.
blocked names each resource the delete would leave, with every reason:
| Reason | What it means |
|---|---|
sole-evidence-for-topic |
The resource is the only live evidence for a topic, judged over the whole set. Sending retireOrphanedTopics: true answers it when those topics can be retired. |
blocked-by-open-issues |
An open issue targets the resource. Sending dismissIssues: true answers it. |
system-organization |
The resource belongs to the system organization. No answer lifts this. |
lessonsClosing and lessonsStaying are judged over the whole set. Each has a
count and a short preview of { id, title }. learnersInProgress is how
many people are part-way through a lesson the delete itself would close.
inFlightAccessRequired is true when that count is above zero, or when
retiring the topics below would close a lesson someone is part-way through.
On organization scope, orphanedTopics names topics that would be left with no
evidence (topics), topics that cannot be retired and why (blocked, with
not-found, already-retired, topic-retired or not-active), and the
resources holding them up (content). orphanedTopics.lessonsClosing is the
lessons retiring those topics would leave with no surviving topic. A lesson
built from a topic has no content id, so it is not in lessonsClosing above.
orphanedTopics.learnersInProgress is how many people are part-way through
those lessons. openIssues names how many open issues stand in the way,
whether dismissing them would also close an issue that names something else
(spansOtherContent), and which resources those issues block. On team scope
those two are empty, and a blocked guide stays blocked.
Delete resources
Section titled “Delete resources”POST /v1/content/deletions
Deletes the resources once every blocked reason is answered. Lessons this empties are closed. A lesson that still has other material stays open: a curated one is rebuilt, and a guided one is marked out of date.
curl -X POST "https://api.mereon.ai/v1/content/deletions" \ -H "Authorization: Bearer $MEREON_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "contentIds": ["cnt_…"], "inFlightAccess": "keep", "retireOrphanedTopics": true }'| Field | Type | Notes |
|---|---|---|
contentIds |
string[] | The same ids you previewed, 1 to 25. |
inFlightAccess |
string | keep leaves people part-way through a closing lesson going. revoke stops them. Required when learnersInProgress is above zero. Also required when retireOrphanedTopics is true and orphanedTopics.learnersInProgress is above zero. When the flag is true only because of those topics, and you are not retiring them, leave it out. |
dismissIssues |
boolean | Dismiss the open issues that block these resources. Leave it out, or send false, unless you mean to dismiss them. |
retireOrphanedTopics |
boolean | Retire topics this would leave with no evidence. Leave it out, or send false, unless you mean to retire them. When there are such topics, you also need permission to retire topics. |
A field the body does not take is a 400, so a misspelt field is refused
rather than ignored. Naming the same id twice is a 400 as well.
{ "results": [ { "contentId": "cnt_…", "title": "Returns policy", "outcome": "deleted" } ], "topicsRetired": 1, "issuesDismissed": 0, "complete": true}results follows the order of contentIds. outcome is deleted,
unshared or kept. An organization admin’s success is deleted. A team
admin’s success on a video, audio recording or document is unshared, which
takes it off the teams they administer. A guide’s success is deleted. A
resource that was already gone by the time the delete ran is deleted.
kept means that resource was left in place, and reason says why.
complete is true when every result is deleted or unshared.
topicsRetired and issuesDismissed count what this call already did. When a
later resource is kept, those earlier writes stay and complete is false:
an issue can be filed again, and a delete cannot be taken back.
The call is refused before anything changes when a resource is still blocked
(409), when people are part-way through a closing lesson and inFlightAccess
is missing (400), or when retiring topics was asked and you may not retire
them (403). When more than one of these applies, the 409 is what you see
first.
Errors
Section titled “Errors”| Status | When |
|---|---|
400 |
The body is invalid, an id is repeated, or people are part-way through a lesson this would close and inFlightAccess is missing. |
403 |
The token lacks content:delete, you may not delete resources, you may not delete one of these resources, or you asked to retire topics and may not. |
404 |
A resource is not one you can see, or the set names an id that does not exist. |
409 |
A resource is still blocked with the answers given. details.blocked names each one and its reasons. Nothing is deleted. |
429 |
Over the rate limit. Retry-After says when to try again. |
Both routes are limited to 30 calls a minute and 300 an hour per connection.
The MCP tools preview_content_deletion and delete_content are held to the
same numbers, counted per tool. Each resource removed or taken off a team is
recorded in the audit log.