Connections

Connected sources, their cursors, the sync batch contract, and what a revoke does immediately.

What a connection is

A connection is a durable record of a source you run: a file server, an S3, R2 or MinIO bucket. The mode is always local_agent, and that word carries the whole security posture — the agent runs in your environment and pushes outward; TAVONEL reaches into nothing. secretReference must be null, because a local agent uses its own workload credentials and we never hold them. configuration carries only non-secret selectors: a bucket, a prefix, a region, a root label.

GET/connectionsScope connections:read

Tenant-scoped durable source connections and their committed cursor state. Takes no paging parameters. The cursor is opaque: it is a sha256 over the collector's own position, and the only supported way to advance it is to send a batch whose `previousCursorSha256` matches the committed one.

curl -sS -X GET https://tavonel.com/api/v1/connections \
  -H "Authorization: Bearer $TAVONEL_API_KEY"
StatusResponse
200The workspace's connections, with the committed cursor on each.
401AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
403API_SCOPE_REQUIRED — The key authenticated and does not carry the scope this operation requires. The request was refused rather than answered with less. PILOT_ACCESS_REQUIRED — The credential is valid and the workspace it names is not admitted to TAVONEL.
503DEVELOPER_STORE_READ_FAILED — The developer store could not be read. DEVELOPER_STORE_NOT_CONFIGURED — The developer store is not configured. DEVELOPER_STORE_BINDING_INVALID — A stored row did not validate, so it was refused rather than returned partially.
POST/connectionsScope connections:write

Registers a local-agent file-server, S3, R2 or MinIO source. Credentials stay in the customer environment: `secretReference` must be null, because a local agent uses its own workload credentials and TAVONEL never holds them. The agent pushes outward; nothing here reaches into your network.

curl -sS -X POST https://tavonel.com/api/v1/connections \
  -H "Authorization: Bearer $TAVONEL_API_KEY"
StatusResponse
201The durable connection record, with an empty cursor.
400CONNECTION_INPUT_INVALID — The connection body did not match ConnectionInput. INVALID_JSON — The body was not parseable JSON.
401AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
403API_SCOPE_REQUIRED — The key authenticated and does not carry the scope this operation requires. The request was refused rather than answered with less. PILOT_ACCESS_REQUIRED — The credential is valid and the workspace it names is not admitted to TAVONEL.
413REQUEST_TOO_LARGE — The JSON body exceeded the route's bound.
503CONNECTION_CREATE_FAILED — The connection could not be recorded. DEVELOPER_STORE_NOT_CONFIGURED — The developer store is not configured.

The cursor, and what it is made of

Each connection carries one committed cursor, published as cursorSha256 and written sha256: followed by 64 hex characters. It is opaque: it is a digest over the collector's own position, not a timestamp, a page number or an offset you can construct. A connection that has never synced carries null.

The only way to move it is to send a batch whose previousCursorSha256 equals the committed value. That is an optimistic lock, and it is what stops two collectors from both advancing one connection: the second one's batch does not match, the whole batch is refused with 409 CONNECTION_BATCH_CONFLICT, and nothing is applied. Re-read the cursor and rebuild from it — never retry the same batch against a moved cursor.

The sync batch contract

FieldWhat it carries
batchIdA UUID you choose. Replaying the identical batchId is idempotent — delivery is at-least-once and this is the consumer that makes it exactly-once. The response says which happened: status is applied or replayed.
previousCursorSha256The cursor as you last read it, or null for a connection that has never synced. The optimistic lock.
nextCursorSha256Where the collector stands after this batch. Committed only if every event in the batch is accepted.
manifestSha256A digest over the event set, so a truncated or reordered batch is refused rather than half-applied.
eventsUp to 5,000 ConnectionEvent objects.

A ConnectionEvent is one observed change at the source. kind is added, changed or deleted. nativeId is the source's own identifier, stable across revisions — an object key, a path, a file id. revision is the source's own version marker: an ETag, an mtime, a version id. Every field is required and several are explicitly nullable, which is the point: a collector that cannot compute a digest sends contentSha256: null rather than omitting the field, so "not known" and "not sent" are different states the server can tell apart.

documentId and sourceIdempotencyKey travel together. Where the source type is qualified, the agent first requests an upload capability with x-tavonel-source-idempotency-key set to a sha256 over the source event, which makes the document id deterministic — a retried collection converges on one document instead of two. The sync batch then names that same pair, and the server revalidates it rather than trusting it.

POST/connections/{id}/syncScope connections:sync

Applies one batch of source events and advances the cursor. `previousCursorSha256` must match the committed cursor, so two collectors cannot both advance it; a mismatch is a 409 and nothing is applied. Replaying an identical `batchId` is idempotent — delivery is at-least-once and this is the consumer that makes it exactly-once.

curl -sS -X POST https://tavonel.com/api/v1/connections/{id}/sync \
  -H "Authorization: Bearer $TAVONEL_API_KEY"
StatusResponse
200The cursor transition, applied or idempotently replayed. status: replayed means this exact batch had already been applied and nothing changed.
400CONNECTION_BATCH_INVALID — The sync batch did not match ConnectionBatch. CONNECTION_ID_INVALID — The connection id was not a UUID. SOURCE_IDENTITY_INVALID — The event's nativeId/revision pair did not validate. SOURCE_DIGEST_REQUIRED — An event carried bytes with no contentSha256. SOURCE_METADATA_INVALID — Event metadata did not validate. INVALID_JSON — The body was not parseable JSON.
401AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
404CONNECTION_NOT_FOUND — No such connection in this workspace.
409CONNECTION_BATCH_CONFLICT — The batch's previousCursorSha256 does not match the committed cursor — another sync moved it. CONNECTION_CURSOR_CONFLICT — Two batches tried to advance the same cursor. SOURCE_CURSOR_STALE — The cursor the batch carries is behind the committed one. SOURCE_DIGEST_CONFLICT — Two events declare different digests for the same revision. SOURCE_DIGEST_MISMATCH — The bytes do not hash to the digest the event declared. SOURCE_VERSION_DIGEST_CONFLICT — A version is already recorded with a different digest.
413REQUEST_TOO_LARGE — The JSON body exceeded the route's bound. SOURCE_CURSOR_TOO_LARGE — The cursor value exceeded its bound.
423CONNECTION_NOT_SYNCABLE — The connection is revoked or in a state that does not accept a batch. SOURCE_LIFECYCLE_REVIEW_REQUIRED — A lifecycle transition on this source needs a person.
503CONNECTION_BATCH_FAILED — The batch could not be applied.

Revoking, and what survives it

A revoke takes effect on the next request rather than waiting for a background reindex. Immutable outputs already compiled are retained: a revoke stops future reads, it does not rewrite history, and a World compiled from that source keeps citing the source version it actually read. A revoke that the store could not record answers 503 rather than 204 — it is reported only when it is written.

DELETE/connections/{id}Scope connections:write

Revokes the connection. Access removal takes effect on the next request rather than waiting for a background reindex. Immutable outputs already compiled are retained: a revoke stops future reads, it does not rewrite history.

curl -sS -X DELETE https://tavonel.com/api/v1/connections/{id} \
  -H "Authorization: Bearer $TAVONEL_API_KEY"
StatusResponse
204Connection revoked; immutable outputs retained. No body.
400CONNECTION_ID_INVALID — The connection id was not a UUID.
401AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
404CONNECTION_NOT_FOUND — No such connection in this workspace.
503CONNECTION_REVOKE_FAILED — The revoke could not be recorded, so it is not reported as done. Immutable outputs are retained by design when a revoke does succeed.

OAuth connectors

Where a provider is configured, a connection can be created through OAuth instead of a local agent. The authorization is single-use and PKCE, and it fails closed: unless both the provider client and the managed secret broker are configured, no authorization is started, because an authorization that cannot store a refresh secret is an authorization that ends in a broken connection. A revoke deletes the stored refresh secret and is reported as done only when the secret is actually gone.

GET/oauth-connectors

Lists configured provider readiness and tenant OAuth connections. Provider credentials are never returned. A provider whose client is not configured reports `configured: false` rather than being hidden.

# Browser session only. A developer API key is refused on this route.
curl -sS -X GET https://tavonel.com/api/v1/oauth-connectors \
  -H "Authorization: Bearer $TAVONEL_SESSION_JWT"
StatusResponse
200Provider readiness and the workspace's connections.
401AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
503OAUTH_STORE_UNAVAILABLE — The OAuth store could not be reached. OAUTH_STORE_NOT_CONFIGURED — The OAuth store is not configured.
POST/oauth-connectors/authorize

Creates a single-use PKCE authorization. Fails closed unless the provider client and the managed secret broker are both configured — an authorization that cannot store a refresh secret is not started.

# Browser session only. A developer API key is refused on this route.
curl -sS -X POST https://tavonel.com/api/v1/oauth-connectors/authorize \
  -H "Authorization: Bearer $TAVONEL_SESSION_JWT"
StatusResponse
200A short-lived provider authorization URL. Single-use: a second visit to it is refused.
400OAUTH_CONNECTOR_INPUT_INVALID — The authorization body did not match OAuthConnectorAuthorizationInput. INVALID_JSON — The body was not parseable JSON.
401AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
413REQUEST_TOO_LARGE — The JSON body exceeded the route's bound.
503OAUTH_PROVIDER_NOT_CONFIGURED — The provider's client is not configured. Fails closed rather than starting an authorization that cannot complete. OAUTH_SECRET_BROKER_NOT_CONFIGURED — The managed secret broker is not configured, so no refresh secret could be stored — or, on a revoke, deleted. OAUTH_AUTHORIZATION_START_FAILED — The single-use PKCE authorization could not be created.
DELETE/oauth-connectors/connections/{id}

Deletes the stored refresh secret and revokes the connection. Reported as done only when the secret is actually gone — a revoke that cannot be proven answers 503 rather than 204.

# Browser session only. A developer API key is refused on this route.
curl -sS -X DELETE https://tavonel.com/api/v1/oauth-connectors/connections/{id} \
  -H "Authorization: Bearer $TAVONEL_SESSION_JWT"
StatusResponse
204Refresh secret deleted and connection revoked. No body.
400OAUTH_CONNECTION_ID_INVALID — The OAuth connection id was not a UUID.
401AUTH_REQUIRED — No credential was presented, or the bearer token is not a key TAVONEL issued. This is what an unauthenticated request to any scoped route returns.
404OAUTH_CONNECTION_NOT_FOUND — No such OAuth connection in this workspace.
503OAUTH_SECRET_REVOCATION_FAILED — The refresh secret could not be deleted, so the revoke was not reported as done. OAUTH_SECRET_BROKER_NOT_CONFIGURED — The managed secret broker is not configured, so no refresh secret could be stored — or, on a revoke, deleted.

Availability by provider

Note Connector availability differs by provider and by workspace, and listOAuthConnectors reports configured: false for a provider whose client TAVONEL does not hold rather than hiding it. The Integrations page states which are live; this page does not restate it, because two pages saying different things about the same connector is how that goes wrong.

API version 2026-09-02.1 · reviewed 11 September 2026

Something here out of date or wrong? Report an issue with this page.