**Connection types** is where you decide which kinds of source your customers are allowed to connect. It is a screen inside Context Link, at **`/white_label/connection_activations`**, listed in the left rail. Before your product can connect a customer's mailbox or their Drive, that source type has to be turned on here.

This is the one screen in the guide that is not read-only, and it is the only place the fleet's source types are set. Everything after it happens over the API, inside your product: [creating connections](/docs/white-label/connect-source), [checking them](/docs/white-label/connection-status) and [removing them](/docs/white-label/disconnect-source).

It is visible to **organisation admins on the white-label plan**. It is deliberately not the same thing as your own team's connections screen. What you set here is what your *customers* may connect, never what your organisation indexes for itself.

## What the screen shows

Three groups, in one list.

| Group | What it is |
|---|---|
| **Always on** | Website. Every customer has it, you do not turn it on, and you cannot withdraw it. |
| **Active sources** | Types you have turned on, with whose OAuth app is on the consent screen, how many of your customers hold one, and the keys. |
| **Available to turn on** | Everything else you could offer, each with its credential form where it needs one. |

The number against each row counts **customers holding that type**, not connections. One customer with three YouTube channels counts once. Per-customer detail lives on the [fleet screen](/docs/white-label/in-app-screens), not here.

### Website is always on

Website sits in its own group with a count and no controls. Every customer may hold a website connection whether or not you ever open this screen, so there is nothing here to turn on. Most are created from the `site_url` you pass when you [provision the account](/docs/white-label/create-account). You can also connect one later with [`PUT .../connections/:connection_uid`](/docs/white-label/connect-source) and `connection_type: "site"`. Either route gives that customer one website, and only one.

Withdrawing the type is what the screen refuses, because it would purge the core of every customer's index. The route refuses it as well, so there is no way to reach it by hand.

Memory and [custom connections](/docs/white-label/create-connection) are not on the screen at all. They are infrastructure every account gets rather than choices you make.

**Files is deliberately not offerable.** It is a browser upload with no API surface your customer could push into, and custom connections already cover you pushing content in on their behalf.

## The types you can turn on

| Source | Needs your OAuth app | What your customer supplies |
|---|---|---|
| Email | No | Address, IMAP password, server, optional port |
| Notion | **Yes** | Consent at Notion |
| Google Drive | **Yes** | Consent at Google |
| OneDrive | **Yes** | Consent at Microsoft |
| Basecamp | **Yes** | Consent at Basecamp |
| monday.com | No | An API token they paste, optional workspace id |
| YouTube | No | A channel handle |
| Web Mentions | No | Brand name and web domain |

**monday.com is a pasted token, not OAuth.** Monday's tokens are long-lived with no refresh, so there is no app to register and no consent screen. Your customer copies a token out of monday.com and you post it like any other setup field.

The exact field names and the request that creates each one are on [Connect a source](/docs/white-label/connect-source).

## Your own OAuth app is required

Four of the types need an OAuth app behind them. It has to be **yours**: the type will not turn on until you have entered every required field, and there is no option to run it on Context Link's app instead.

- **Why there is no fallback.** A provider only sends a customer back to a redirect URI registered on the same OAuth app as the `client_id` that started the flow. Our own Notion, Microsoft and Basecamp apps are registered for our own sign-in callbacks, not for the fleet callback below, so a customer sent through them would be turned away at the provider with a redirect URI error.
- **What you get for it.** The consent screen says *your* company, which is the point of the white-label plan: your customer never sees us.
- **Types turned on before this rule.** A type that was enabled without its complete configuration stays enabled, so nothing already indexed is purged, but it takes no new connections: the connect and re-authorise calls answer `409 partner_credentials_required` until you complete it. Customers already connected keep syncing.

### Google Drive: OAuth plus Picker

Google Drive needs four values from one Google Cloud project:

- **OAuth client ID and client secret** for the server-side consent and token exchange.
- **Picker API key** for Google Picker in your customer's browser.
- **Cloud project number** (the numeric project id) passed to Picker as its app id.

Set them up in this order. The Connection types screen shows the same steps under **What to set up in Google** on the Google Drive card.

1. **Enable the Google Drive API and Google Picker API** (APIs & Services > Library). Do this before creating the API key: the key's API restrictions list only offers APIs already enabled in the project, so it is empty otherwise.
2. **Configure the OAuth consent screen** under your own brand, since your customers see it. Publish it to production; in testing mode only listed test users can connect.
3. **Create the OAuth client**: Create credentials > OAuth client ID, application type **Web application**, with Context Link's callback (below) as an authorised redirect URI. Its client ID and secret go into the first two fields.
4. **Create the Picker API key**: Create credentials > API key. Under API restrictions, allow the Google Picker API and Google Drive API. Under application restrictions, choose **Websites** and add your production app origin (for example `https://app.example.com/*`) plus `https://docs.google.com/*`. Picker runs in your customer's browser inside your product, so the origin is your app, not context-link.ai. Add a dev or ngrok origin while you test.
5. **Copy the Cloud project number** from IAM & Admin > Settings or the project dashboard: the numeric project number, not the project ID.

The project number, OAuth client and API key must belong to the same project.

Context Link requests `email`, `profile` and Google's non-sensitive `drive.file` scope. That scope grants access only to files the customer chooses in Picker; it does not require restricted-scope verification or an annual third-party security assessment. You still configure and publish the OAuth consent screen under your own brand.

After consent, Google returns the customer to your `return_url` with `connection_status=selection_required`. Your backend fetches the Picker configuration and your browser UI lets the customer choose files before the connection is authorised. The complete flow is on [Connect a source](/docs/white-label/connect-source#complete-google-drive-with-picker).

Each field carries a **Where to find it** link straight to the provider's credentials page: Google Cloud console, Microsoft Entra, Notion integrations, 37signals launchpad. Registering the app is a link away rather than a support ticket. Google Drive's fields also link to their step in **What to set up in Google**.

> **Provider setup is yours to maintain.** The consent screen shows your brand because it is your OAuth client. Complete each provider's normal publishing and branding requirements. Google Drive's `drive.file` access is non-sensitive; adding broader Drive or Gmail scopes to the same consent request can create separate verification requirements.

Types that need no keys turn on with one click. Types that need keys show the form first, with the redirect URI to whitelist beside it, and refuse to turn on until every field is filled. Google Drive requires all four Google values.

### Keys are write-only

A stored key is reported as **set** and never rendered back into the page. You can replace it, you cannot read it. That is the opposite of your [provisioning token](/docs/white-label/getting-started), which is retrievable on purpose. A third-party OAuth secret has no such need, and rendering it would only put it in browser caches and screenshots.

What that means in practice, before you touch the form:

- **Blank means "keep what is stored", not "clear it".** Because the field is never populated, an untouched field is always blank, so saving an unchanged form leaves your keys exactly as they were.
- **There is no clearing.** An OAuth type that is turned on needs your keys, so removing them is a withdrawal, not an edit.
- **Rotating the secret alone is safe.** A refresh token is bound to the `client_id` that issued it; the secret only authenticates your app at the provider's token endpoint. We read both fresh on every refresh, so the next one presents your new secret against the same `client_id` and succeeds. Nobody has to reconnect.
- **Rotating only the Google Picker API key is safe.** Existing OAuth grants are unchanged. Save the replacement before disabling the old key, and keep the same browser and API restrictions.
- **Changing the `client_id` is a fleet-wide reconnect campaign.** Every refresh token your customers hold was issued by the old OAuth app and is worthless to a different one. Those connections fail their next refresh, land in `auth_failed` and need [re-authorising](/docs/white-label/connect-source#re-authorising-a-dead-connection) one by one. The same is true of deleting the app in the provider's console. Three things count as changing the app, and the last one is the easy one to miss:
    - pointing the activation at a different OAuth client.
- **Google's project number must match the Picker key and OAuth client.** Replacing it with an unrelated project breaks Picker rather than migrating grants.
- **Configuration goes in as a set.** A `client_id` without its secret—or Google OAuth values without matching Picker values—is incomplete, so a half-filled form is refused rather than stored.

Do any of these when you have somewhere to route the `connection.auth_failed` [webhooks](/docs/white-label/webhooks).

### Register our redirect URI on your own app

Your keys mean your OAuth app, so the provider sends the customer back to us through a
redirect URI that has to be whitelisted on **your** app. Add the one for that type before you
turn it on. The screen shows the exact value with a copy button next to the key fields.

| Type | Redirect URI to register |
|---|---|
| Notion | `https://www.context-link.ai/api/v1/oauth/callback/notion` |
| Google Drive | `https://www.context-link.ai/api/v1/oauth/callback/google_doc` |
| OneDrive | `https://www.context-link.ai/api/v1/oauth/callback/one_drive` |
| Basecamp | `https://www.context-link.ai/api/v1/oauth/callback/basecamp` |

Skipping this does not fail on our side. Your customer is turned away at the provider's own
consent screen with an error we never see, so there is nothing for us to report back to you.

The code exchange needs a client secret, which is why the provider returns to us rather than
to you. Where the customer lands afterwards is still yours: that is the `return_url` you send
on the [connect call](/docs/white-label/connect-source), carried through the flow in a signed
payload so it cannot be tampered with.

## Withdrawing a type purges your whole fleet

Withdrawing a source type is the most destructive action available to you anywhere in this product. **Every connection of that type, belonging to every one of your customers, is destroyed**, and with it every document indexed from those connections and every embedded passage of those documents. There is no frozen middle state and nothing to restore from.

The screen is built to make that impossible to do by accident:

1. **Withdraw** opens a modal carrying the **real counts, computed before it opens**: how many connections, how many posts, how many of your customers. Never a generic "are you sure?".
2. Above **10 connections** across the fleet you must **type the source's name** to confirm. Below it, the counts alone are the confirmation.
3. The deletion then runs **in the background**, so a fleet of ninety thousand posts does not depend on a browser tab staying open.
4. **An audit row is written before anything is destroyed**, recording who withdrew what, when, and the counts. Somebody will ask later, and by then the content is gone.
5. You receive **one org-level [`connection_type.revoked` webhook](/docs/white-label/webhooks)** at your organisation's default webhook URL, carrying the type and the number of connections destroyed. Not one per customer.

**Your keys survive the withdrawal.** The type moves back down to *Available to turn on* marked as still holding your keys, so turning it back on later is one click. What does not survive is your customers' indexed content: they would have to reconnect the source and re-sync from nothing.

Withdrawal is not the tool for a single customer who wants one source gone. That is [`DELETE .../connections/:connection_uid`](/docs/white-label/disconnect-source), which touches one connection and nobody else's.

## Limits that come with turning a type on

Turning a type on does not make it unbounded. Syncing spends your question allowance, and that is **one pool shared across your whole fleet, sized at 5,000 questions per bundle per month**. Without the caps below, one customer with an enormous mailbox could spend that pool on everybody's behalf.

| Limit | Value |
|---|---|
| Connections per customer, all types | 10, and the memory connection is exempt |
| Connections of one type per customer | 5, counting toward the 10 |
| Websites per customer | 1, counting toward the 10 |
| Custom connections per customer | 6, counting toward the 10 |
| Documents per sync per connection | 500 by default, 30 for YouTube, 50 for Web Mentions |

**10 is the binding ceiling.** The per-type numbers are maxima within it, not slices that add up to it. A customer can hold 6 custom connections or 5 mailboxes, but not both, because the total still has to come in at 10. The memory connection is the one exception: it never counts.

If a per-connection document ceiling needs turning down for one heavy customer, ask us. It is a single field on that connection rather than a cap on everyone using that type.
