GraphQL Mutations
All mutations require an Authorization: Bearer <token> header. Every mutation is scoped to the authenticated user’s data.
createSource
Section titled “createSource”Create a new source to define an upstream for ingestion.
createSource(input: CreateSourceInput!): Source!Input Fields
Section titled “Input Fields”| Field | Type | Required | Description |
|---|---|---|---|
sourceType | String! | Yes | The type of source (e.g., "rss", "hacker-news", "podcast"). |
name | String! | Yes | Display name for the source. |
description | String | No | Optional description of the source. |
icon | String | No | Optional icon identifier or emoji. |
config | JSON! | Yes | Source-specific configuration (e.g., feed URL, filters). Preferences only — never credentials. |
Return Type
Section titled “Return Type”Returns the created Source.
Example
Section titled “Example”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" } } } }'updateSource
Section titled “updateSource”Update an existing source’s settings. Only the fields you include in the input are changed.
updateSource(id: ID!, input: UpdateSourceInput!): Source!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The source ID to update. |
Input Fields
Section titled “Input Fields”| Field | Type | Required | Description |
|---|---|---|---|
name | String | No | New display name. |
description | String | No | New description. |
config | JSON | No | Updated configuration. Replaces the entire config object. |
Return Type
Section titled “Return Type”Returns the updated Source.
Example
Section titled “Example”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)" } } }'deleteSource
Section titled “deleteSource”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!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The source ID to delete. |
Return Type
Section titled “Return Type”Returns the soft-deleted Source (with deletedAt set).
Example
Section titled “Example”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" } }'restoreSource
Section titled “restoreSource”Restore a soft-deleted source — and its feeds and documents — within the purge grace period. Clears deleted_at.
restoreSource(id: ID!): Source!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The source ID to restore. |
Return Type
Section titled “Return Type”Returns the restored Source.
Example
Section titled “Example”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" } }'pauseSource
Section titled “pauseSource”Mark a source as paused. Sets status: PAUSED so the sync client stops syncing it until it is resumed.
pauseSource(id: ID!): Source!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The source ID to pause. |
Return Type
Section titled “Return Type”Returns the updated Source with status: PAUSED.
Example
Section titled “Example”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" } }'resumeSource
Section titled “resumeSource”Resume a paused source. Sets status: ACTIVE so the sync client resumes syncing it.
resumeSource(id: ID!): Source!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The source ID to resume. |
Return Type
Section titled “Return Type”Returns the updated Source with status: ACTIVE.
Example
Section titled “Example”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" } }'saveDocument
Section titled “saveDocument”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!Input Fields
Section titled “Input Fields”| Field | Type | Required | Description |
|---|---|---|---|
text | String | No | The text content to save. |
url | String | No | URL of the original. If provided without text, the content is fetched. |
title | String | No | Title for the saved document. |
source | String | No | Free-form attribution label (e.g., "clipboard", "share-extension"). |
tags | [String!] | No | Tags to apply to the document. |
Return Type
Section titled “Return Type”Returns the created Document.
Example
Section titled “Example”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"] } } }'addFeed
Section titled “addFeed”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!Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
sourceId | ID! | Yes | The source to add the feed to. |
externalKey | String! | Yes | Stable identifier within the source (feed URL, username, or "default"). Unique per source. |
name | String! | Yes | Display name for the feed. |
config | JSON | No | Feed-specific preferences. Never credentials. |
Return Type
Section titled “Return Type”Returns the created Feed. Use its id as the feedId when calling ingestDocuments.
Example
Section titled “Example”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" } }'pauseFeed
Section titled “pauseFeed”Pause a single feed (status: PAUSED) so the sync client stops syncing it, without affecting the source’s other feeds.
pauseFeed(id: ID!): Feed!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The feed ID to pause. |
Return Type
Section titled “Return Type”Returns the updated Feed with status: PAUSED.
Example
Section titled “Example”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" } }'resumeFeed
Section titled “resumeFeed”Resume a paused feed (status: ACTIVE).
resumeFeed(id: ID!): Feed!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The feed ID to resume. |
Return Type
Section titled “Return Type”Returns the updated Feed with status: ACTIVE. Same request shape as pauseFeed.
deleteFeed
Section titled “deleteFeed”Soft-delete a feed and all its documents (sets deleted_at). Recoverable with restoreFeed until the purge grace period elapses.
deleteFeed(id: ID!): Feed!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The feed ID to delete. |
Return Type
Section titled “Return Type”Returns the soft-deleted Feed (with deletedAt set).
Example
Section titled “Example”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" } }'restoreFeed
Section titled “restoreFeed”Restore a soft-deleted feed and its documents within the purge grace period. Same request shape as deleteFeed.
restoreFeed(id: ID!): Feed!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The feed ID to restore. |
Return Type
Section titled “Return Type”Returns the restored Feed.
ingestDocuments
Section titled “ingestDocuments”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!Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
sourceId | ID! | Yes | The source to ingest into. |
feedId | ID! | Yes | The feed within the source. Use addFeed to create one. |
documents | [IngestDocumentInput!]! | Yes | Array of documents to ingest. Maximum 50 per call. |
cursor | String | No | The feed’s new sync position. Stored on the feed and returned in the result. |
cursorBefore | String | No | The cursor value you last read, for compare-and-swap safety against concurrent syncs. |
Document Input Fields
Section titled “Document Input Fields”| Field | Type | Required | Description |
|---|---|---|---|
externalId | String! | Yes | Unique identifier from the upstream system. Used for deduplication via the (feedId, externalId) pair. |
title | String | No | Document title. |
text | String | No | Full text content. Required unless audioUrl is provided. |
audioUrl | String | No | URL to an audio file for transcription. |
url | String | No | Original URL. |
author | String | No | Document author. |
date | DateTime | No | Original publication or creation date. |
contentType | ContentType | No | The kind of content — see the ContentType enum. Defaults to TEXT. |
tags | [String!] | No | Tags to apply. |
metadata | JSON | No | Arbitrary metadata stored with the document. |
Return Type
Section titled “Return Type”Returns IngestResult with counts of indexed and skipped documents, the updated cursor, and any errors.
Example
Section titled “Example”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" } ] } }'createSyncRun
Section titled “createSyncRun”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!Parameters
Section titled “Parameters”| Parameter | Type | Required | Description |
|---|---|---|---|
sourceId | ID! | Yes | The source that was synced. |
feedId | ID! | Yes | The feed that was synced. |
status | SyncRunStatus! | Yes | RUNNING, SUCCESS, ERROR, or CANCELLED. |
documentsSynced | Int! | Yes | Number of documents ingested in this run. |
cursorBefore | String | No | The feed cursor before the run. |
cursorAfter | String | No | The feed cursor after the run. |
startedAt | DateTime! | Yes | When the run started. |
completedAt | DateTime | No | When it finished. null if still running. |
durationMs | Int | No | Total duration in milliseconds. |
errorMessage | String | No | Error detail when status is ERROR. |
logs | String | No | The run’s transcript, for display in the app. |
Return Type
Section titled “Return Type”Returns the created SyncRun.
deleteDocument
Section titled “deleteDocument”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!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The document ID to delete. |
Return Type
Section titled “Return Type”Returns true on success.
Example
Section titled “Example”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" } }'deleteDocumentsBySource
Section titled “deleteDocumentsBySource”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!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
sourceId | ID! | The source whose documents should be deleted. |
Return Type
Section titled “Return Type”Returns the number of documents deleted as an Int.
Example
Section titled “Example”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" } }'updateDocumentTags
Section titled “updateDocumentTags”Replace the full tag array on a document. This overwrites all existing tags with the new set.
updateDocumentTags(id: ID!, tags: [String!]!): Document!Parameters
Section titled “Parameters”| Parameter | Type | Description |
|---|---|---|
id | ID! | The document ID. |
tags | [String!]! | The new tag array. Pass an empty array to clear all tags. |
Return Type
Section titled “Return Type”Returns the updated Document.
Example
Section titled “Example”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"] } }'