> ## Documentation Index
> Fetch the complete documentation index at: https://docs.seynlabs.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connectors

> Anything that can produce records can feed Seyn: the connector contract, building your own, and the prebuilt catalog.

A connector is not a product SKU. It's a contract. Strip ingestion to first principles and a source system only needs to supply three things: **records with a stable identity, a payload, and a source timestamp**. Everything else (deduplication, normalization into [events](/platform/events), actor identity resolution, [provenance](/platform/provenance), extraction) is Seyn's job, and it's identical for every source.

That has a direct consequence: **the catalog is not the boundary of what Seyn can ingest.** Prebuilt connectors are just connectors we maintain for you. If your data lives somewhere we haven't built for yet, you don't wait for us.

## The contract

Three guarantees hold for every connector, prebuilt or custom:

1. **Read-only, always.** No connector writes to a source system. See [Security](/platform/security).
2. **Idempotent ingestion.** Every record is deduplicated by content hash; re-running a sync never creates duplicates.
3. **Observable syncs.** Every run produces a sync record with per-stage counters, visible on the connector's detail page.

And the division of labour is fixed:

| The connector supplies                                                   | Seyn guarantees                                                  |
| ------------------------------------------------------------------------ | ---------------------------------------------------------------- |
| A stable record ID per item                                              | Content-hash deduplication across every sync                     |
| The raw payload, verbatim                                                | Verbatim preservation as the bottom of the provenance chain      |
| A source timestamp                                                       | Event time = source time, not ingestion time                     |
| A mapping from payloads to events (*who did what to which entity, when*) | Actor identity resolution, the event store, extraction, querying |

## Build your own

A custom connector is that contract, implemented by you, over the **Ingestion API**:

* **Register a source.** `POST /v1/sources` returns a `sourceId` for the system you're bringing in.
* **Push records in batches.** `POST /v1/ingest` takes records shaped as `{ recordId, entityType, payload, sourceUpdatedAt }`, up to 500 at a time. Full dumps work; incremental feeds (everything since a cursor) make re-syncs cheap, and content-hash dedup means re-sending an unchanged record is a no-op.
* **Seyn does the rest.** Dedup, normalization into [events](/platform/events), identity resolution, provenance linking, extraction, and querying treat your records exactly like records from a prebuilt connector. Same chain, same receipts.

That's the whole surface. A CSV export, an internal tool's API, a legacy database, a logistics system we've never heard of: if it can produce records, it can be a connector. Full request and response shapes are in the [API Reference](/api-reference/ingest-records), and the [SDK](/sdk-reference#ingestion) wraps them in typed methods.

```ts theme={null}
const source = await client.sources.create({ name: "Internal CRM", entityTypes: ["deal"] });

await client.ingest({
  sourceId: source.id,
  records: [
    {
      recordId: "deal-4471",
      entityType: "deal",
      sourceUpdatedAt: "2026-06-10T14:03:00Z",
      payload: { name: "Acme Corp renewal", stage: "negotiation", owner: "jane.smith@acme.com" },
    },
  ],
});
```

<Note>
  **Early access.** The Ingestion API and the contract behind it are stable and are the same path our own connectors use, but ingestion requires an API key with the `ingest` scope, granted per organisation during alpha. [Request access](mailto:support@seynlabs.com?subject=Seyn%20custom%20connector) and we'll enable a write-scoped key and onboard your source together.
</Note>

## Prebuilt connectors

Prebuilt connectors add what generic ingestion can't know: each source's auth flow, delta semantics, edit and delete behaviour, and quirks.

| Connector            | What it ingests                                                                  | Auth                   | Sync model                                      |
| -------------------- | -------------------------------------------------------------------------------- | ---------------------- | ----------------------------------------------- |
| **SharePoint**       | Document libraries, with folder-level allow-list policies                        | Microsoft OAuth        | Delta sync, per-drive checkpoint                |
| **Outlook**          | Email, optionally attachments                                                    | Microsoft OAuth        | Delta sync, per-folder checkpoint               |
| **Outlook Calendar** | Meetings, invites, and attendees                                                 | Microsoft OAuth        | Delta sync                                      |
| **Microsoft Teams**  | Channel messages and replies; optional meeting transcripts <sup>In testing</sup> | Microsoft OAuth        | Delta sync, per-channel checkpoint              |
| **Google Drive**     | Documents and shared drives                                                      | Google OAuth           | Incremental change feed                         |
| **Gmail**            | Email and threads                                                                | Google OAuth           | Incremental history sync                        |
| **Google Calendar**  | Meetings, invites, and attendees                                                 | Google OAuth           | Incremental sync tokens                         |
| **Slack**            | Channel messages and threads                                                     | Slack OAuth            | Incremental                                     |
| **Document Inbox**   | Self-serve upload: loose files or ZIP archives                                   | Upload, no credentials | On upload. See [Documents](/platform/documents) |

More connectors land regularly. Anything not on this list can be ingested today as a [custom connector](#build-your-own), or [tell us](mailto:support@seynlabs.com) what you need and don't wait.

## How delta sync works

The Microsoft connectors use Graph **delta queries**: after the initial full sync, each run asks only "what changed since my last checkpoint?"

* **Atomic checkpoints, scoped small.** The delta token is stored per drive, per channel, or per folder, and committed atomically with the records it covers. A crash mid-sync resumes from the last consistent point: never re-ingesting, never skipping.
* **Failure isolation.** One channel or drive failing doesn't abort the others; it's recorded in the sync run and retried next time.
* **Expired tokens self-heal.** When the source invalidates a delta token, the connector transparently restarts a full enumeration, and content-hash dedup makes that resync cheap and duplicate-free.
* **Edits and deletes propagate.** Edited messages update their event in place; deletions soft-delete downstream events rather than breaking the provenance chain.

### Honest limitations

* **Teams: standard channels only.** Private and shared channels sit behind different permission models we haven't validated yet.
* **Teams replies have no delta endpoint** (a Microsoft Graph limitation), so replies are re-pulled when their parent changes.
* **Protected APIs.** Some Teams data sits behind Microsoft's Protected API approval. If a tenant lacks approval, the sync surfaces an explicit terminal status naming the admin action required. It doesn't silently return partial data.
* **System messages are filtered.** Joins, renames, and app-install notices are noise for process extraction and are dropped at ingestion.

## Connector lifecycle

```mermaid theme={null}
flowchart LR
    A["Create connector<br/>(configure + authorize)"] --> B["Sync run"]
    B --> C["Raw records<br/>(deduplicated)"]
    C --> D["Events"]
    D --> E["Extraction run"]
    B -. "per-run counters,<br/>status, errors" .-> F["Sync history"]
```

<Info>
  **Planned: auto-sync.** Per-connector schedules, opt-in post-sync knowledge rebuild, and staleness indicators are specified and coming. See [Status](/status).
</Info>

## Common mistakes

| Symptom                                                | Cause                                                                     | Fix                                                                                                                                        |
| ------------------------------------------------------ | ------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
| Synced data doesn't show up in chat                    | Sync landed raw records, but no extraction run has processed them yet     | Walk the [debugging order](/platform/architecture#when-something-looks-wrong-walk-the-chain-in-order): sync → extraction → library → query |
| Teams sync ends in a terminal error mentioning consent | The tenant hasn't granted admin consent or Protected API approval         | The error names the exact admin action; complete it in the Microsoft tenant and re-run                                                     |
| SharePoint sync ingests less than expected             | Folder policies are an allow-list; paths outside it are skipped by design | Review the connector's folder policy configuration                                                                                         |
| Re-running a sync to "fix" data created no new records | Content-hash dedup recognised everything. That's correct behaviour        | If source data changed, delta sync picks it up; if not, there's nothing new to ingest                                                      |

## Related

<CardGroup cols={2}>
  <Card title="Events" icon="shuffle" href="/platform/events">
    The common schema your records are normalized into.
  </Card>

  <Card title="Documents" icon="file-lines" href="/platform/documents">
    The deepest connector: parsing, extraction, and the upload inbox.
  </Card>
</CardGroup>
