Skip to content

GraphQL Mutations

All mutations require an Authorization: Bearer <token> header. Every mutation is scoped to the authenticated user’s data.

Create a new source to define an upstream for ingestion.

createSource(input: CreateSourceInput!): Source!
FieldTypeRequiredDescription
sourceTypeString!YesThe type of source (e.g., "rss", "hacker-news", "podcast").
nameString!YesDisplay name for the source.
descriptionStringNoOptional description of the source.
iconStringNoOptional icon identifier or emoji.
configJSON!YesSource-specific configuration (e.g., feed URL, filters). Preferences only — never credentials.

Returns the created Source.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation CreateSource($input: CreateSourceInput!) { createSource(input: $input) { id sourceType name status createdAt } }",
"variables": {
"input": {
"sourceType": "rss",
"name": "Tech Blogs",
"description": "Engineering blogs I follow",
"config": { "feedUrl": "https://example.com/feed.xml" }
}
}
}'

Update an existing source’s settings. Only the fields you include in the input are changed.

updateSource(id: ID!, input: UpdateSourceInput!): Source!
ParameterTypeDescription
idID!The source ID to update.
FieldTypeRequiredDescription
nameStringNoNew display name.
descriptionStringNoNew description.
configJSONNoUpdated configuration. Replaces the entire config object.

Returns the updated Source.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation UpdateSource($id: ID!, $input: UpdateSourceInput!) { updateSource(id: $id, input: $input) { id name updatedAt } }",
"variables": {
"id": "src_abc123",
"input": {
"name": "Tech Blogs (Updated)"
}
}
}'

Soft-delete a source and all of its feeds and documents (sets deleted_at). Recoverable with restoreSource until the purge grace period elapses.

deleteSource(id: ID!): Source!
ParameterTypeDescription
idID!The source ID to delete.

Returns the soft-deleted Source (with deletedAt set).

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation DeleteSource($id: ID!) { deleteSource(id: $id) { id name status deletedAt } }",
"variables": { "id": "src_abc123" }
}'

Restore a soft-deleted source — and its feeds and documents — within the purge grace period. Clears deleted_at.

restoreSource(id: ID!): Source!
ParameterTypeDescription
idID!The source ID to restore.

Returns the restored Source.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation Restore($id: ID!) { restoreSource(id: $id) { id name status } }",
"variables": { "id": "src_abc123" }
}'

Mark a source as paused. Sets status: PAUSED so the sync client stops syncing it until it is resumed.

pauseSource(id: ID!): Source!
ParameterTypeDescription
idID!The source ID to pause.

Returns the updated Source with status: PAUSED.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation PauseSource($id: ID!) { pauseSource(id: $id) { id name status } }",
"variables": { "id": "src_abc123" }
}'

Resume a paused source. Sets status: ACTIVE so the sync client resumes syncing it.

resumeSource(id: ID!): Source!
ParameterTypeDescription
idID!The source ID to resume.

Returns the updated Source with status: ACTIVE.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation ResumeSource($id: ID!) { resumeSource(id: $id) { id name status } }",
"variables": { "id": "src_abc123" }
}'

Quick-save a piece of content to your knowledge base. Automatically creates a “Manual Saves” source if one does not already exist.

saveDocument(input: SaveDocumentInput!): Document!
FieldTypeRequiredDescription
textStringNoThe text content to save.
urlStringNoURL of the original. If provided without text, the content is fetched.
titleStringNoTitle for the saved document.
sourceStringNoFree-form attribution label (e.g., "clipboard", "share-extension").
tags[String!]NoTags to apply to the document.

Returns the created Document.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation Save($input: SaveDocumentInput!) { saveDocument(input: $input) { id title tags indexedAt source { id name } } }",
"variables": {
"input": {
"title": "Interesting article on distributed systems",
"url": "https://example.com/article",
"text": "Full text of the article goes here...",
"source": "web",
"tags": ["distributed-systems", "architecture"]
}
}
}'

Add a feed (a publication, channel, or stream) to a source. A source needs at least one feed before you can ingest into it; single-feed sources use one feed with externalKey: "default".

addFeed(sourceId: ID!, externalKey: String!, name: String!, config: JSON): Feed!
ParameterTypeRequiredDescription
sourceIdID!YesThe source to add the feed to.
externalKeyString!YesStable identifier within the source (feed URL, username, or "default"). Unique per source.
nameString!YesDisplay name for the feed.
configJSONNoFeed-specific preferences. Never credentials.

Returns the created Feed. Use its id as the feedId when calling ingestDocuments.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($sourceId: ID!, $externalKey: String!, $name: String!) { addFeed(sourceId: $sourceId, externalKey: $externalKey, name: $name) { id name } }",
"variables": { "sourceId": "src_abc123", "externalKey": "default", "name": "Main feed" }
}'

Pause a single feed (status: PAUSED) so the sync client stops syncing it, without affecting the source’s other feeds.

pauseFeed(id: ID!): Feed!
ParameterTypeDescription
idID!The feed ID to pause.

Returns the updated Feed with status: PAUSED.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($id: ID!) { pauseFeed(id: $id) { id name status } }",
"variables": { "id": "feed_def456" }
}'

Resume a paused feed (status: ACTIVE).

resumeFeed(id: ID!): Feed!
ParameterTypeDescription
idID!The feed ID to resume.

Returns the updated Feed with status: ACTIVE. Same request shape as pauseFeed.


Soft-delete a feed and all its documents (sets deleted_at). Recoverable with restoreFeed until the purge grace period elapses.

deleteFeed(id: ID!): Feed!
ParameterTypeDescription
idID!The feed ID to delete.

Returns the soft-deleted Feed (with deletedAt set).

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation($id: ID!) { deleteFeed(id: $id) { id deletedAt } }",
"variables": { "id": "feed_def456" }
}'

Restore a soft-deleted feed and its documents within the purge grace period. Same request shape as deleteFeed.

restoreFeed(id: ID!): Feed!
ParameterTypeDescription
idID!The feed ID to restore.

Returns the restored Feed.


Batch ingest documents into a specific feed within a source. This is the primary way to push data into Trove programmatically. Documents with the same (feedId, externalId) pair are skipped to prevent duplicates.

ingestDocuments(
sourceId: ID!
feedId: ID!
documents: [IngestDocumentInput!]!
cursor: String
cursorBefore: String
): IngestResult!
ParameterTypeRequiredDescription
sourceIdID!YesThe source to ingest into.
feedIdID!YesThe feed within the source. Use addFeed to create one.
documents[IngestDocumentInput!]!YesArray of documents to ingest. Maximum 50 per call.
cursorStringNoThe feed’s new sync position. Stored on the feed and returned in the result.
cursorBeforeStringNoThe cursor value you last read, for compare-and-swap safety against concurrent syncs.
FieldTypeRequiredDescription
externalIdString!YesUnique identifier from the upstream system. Used for deduplication via the (feedId, externalId) pair.
titleStringNoDocument title.
textStringNoFull text content. Required unless audioUrl is provided.
audioUrlStringNoURL to an audio file for transcription.
urlStringNoOriginal URL.
authorStringNoDocument author.
dateDateTimeNoOriginal publication or creation date.
contentTypeContentTypeNoThe kind of content — see the ContentType enum. Defaults to TEXT.
tags[String!]NoTags to apply.
metadataJSONNoArbitrary metadata stored with the document.

Returns IngestResult with counts of indexed and skipped documents, the updated cursor, and any errors.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation Ingest($sourceId: ID!, $feedId: ID!, $documents: [IngestDocumentInput!]!, $cursor: String) { ingestDocuments(sourceId: $sourceId, feedId: $feedId, documents: $documents, cursor: $cursor) { documentsIndexed documentsSkipped cursor errors { externalId message } } }",
"variables": {
"sourceId": "src_abc123",
"feedId": "feed_def456",
"cursor": "page-2",
"documents": [
{
"externalId": "article-001",
"title": "Understanding Raft Consensus",
"text": "Full article text...",
"url": "https://example.com/raft",
"author": "Jane Doe",
"date": "2026-03-20T10:00:00Z",
"contentType": "TEXT",
"tags": ["distributed-systems", "consensus"]
},
{
"externalId": "article-002",
"title": "Paxos Made Simple",
"text": "Another article...",
"author": "John Smith",
"date": "2026-03-21T14:30:00Z",
"contentType": "TEXT"
}
]
}
}'

Record a sync run for history and health reporting. A sync client calls this after each sync (success or failure) so the run appears in Source.syncRuns and the dashboard. The ingest pipeline does not create sync runs automatically — the client decides what counts as a run.

createSyncRun(
sourceId: ID!
feedId: ID!
status: SyncRunStatus!
documentsSynced: Int!
cursorBefore: String
cursorAfter: String
startedAt: DateTime!
completedAt: DateTime
durationMs: Int
errorMessage: String
logs: String
): SyncRun!
ParameterTypeRequiredDescription
sourceIdID!YesThe source that was synced.
feedIdID!YesThe feed that was synced.
statusSyncRunStatus!YesRUNNING, SUCCESS, ERROR, or CANCELLED.
documentsSyncedInt!YesNumber of documents ingested in this run.
cursorBeforeStringNoThe feed cursor before the run.
cursorAfterStringNoThe feed cursor after the run.
startedAtDateTime!YesWhen the run started.
completedAtDateTimeNoWhen it finished. null if still running.
durationMsIntNoTotal duration in milliseconds.
errorMessageStringNoError detail when status is ERROR.
logsStringNoThe run’s transcript, for display in the app.

Returns the created SyncRun.


Delete a single document. This is a cascading delete that removes the document record, its stored full text, and its search index vector. This action is irreversible.

deleteDocument(id: ID!): Boolean!
ParameterTypeDescription
idID!The document ID to delete.

Returns true on success.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation DeleteDoc($id: ID!) { deleteDocument(id: $id) }",
"variables": { "id": "doc_abc123" }
}'

Delete all documents belonging to a source. Useful for clearing a source’s data before a full re-sync. This action is irreversible.

deleteDocumentsBySource(sourceId: ID!): Int!
ParameterTypeDescription
sourceIdID!The source whose documents should be deleted.

Returns the number of documents deleted as an Int.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation ClearSource($sourceId: ID!) { deleteDocumentsBySource(sourceId: $sourceId) }",
"variables": { "sourceId": "src_abc123" }
}'

Replace the full tag array on a document. This overwrites all existing tags with the new set.

updateDocumentTags(id: ID!, tags: [String!]!): Document!
ParameterTypeDescription
idID!The document ID.
tags[String!]!The new tag array. Pass an empty array to clear all tags.

Returns the updated Document.

Terminal window
curl -X POST https://api.ontrove.sh/graphql \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"query": "mutation UpdateTags($id: ID!, $tags: [String!]!) { updateDocumentTags(id: $id, tags: $tags) { id title tags } }",
"variables": {
"id": "doc_abc123",
"tags": ["architecture", "must-read", "2026"]
}
}'