Skip to content

Sync API

Trove ingests content through the GraphQL API — there is no separate REST endpoint. A sync client (the Trove Mac app, or your own code) fetches content from an upstream and pushes it in. All requests go to https://api.ontrove.sh/graphql with an Authorization: Bearer <token> header.

A document belongs to a feed, which belongs to a source. So a sync client:

  1. Ensures a sourcecreateSource (once per connected thing).
  2. Ensures a feed within it — addFeed (once per publication/stream; a single-feed source uses one feed with externalKey: "default").
  3. Pushes documentsingestDocuments, passing both the sourceId and the feedId.

Steps 1–2 run once; subsequent syncs just call 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!, $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": "2026-03-25T12:00:00Z",
"documents": [
{
"externalId": "post-12345",
"title": "Interesting Article",
"text": "Full text content...",
"url": "https://example.com/blog/post-12345",
"author": "Jane Smith",
"date": "2026-03-25T12:00:00Z",
"contentType": "TEXT",
"tags": ["tech", "ai"],
"metadata": { "likes": 42 }
}
]
}
}'

Send up to 50 documents per call. See ingestDocuments for the full field reference and IngestDocumentInput for the document shape.

cursor records where the feed’s sync left off. It’s stored on the feed and echoed back in the result; on the next run, read it from Feed.cursor to resume. Trove parses it into a FeedWatermark, so the app and tools can show “synced through <date>”. Pass cursorBefore (the value you last read) for compare-and-swap safety against concurrent syncs.

Documents with the same (feedId, externalId) pair are skipped — re-submitting a batch never creates duplicates.

To ingest audio, send a document with audioUrl instead of text. Trove transcribes it asynchronously using a speech-to-text model and indexes the resulting transcript with contentType: TRANSCRIPT.

NeedUse
Record a sync run for historycreateSyncRun
List sources and their healththe sources query and stats
Delete a documentdeleteDocument