RAG White-Label

Connect a source

Connect one customer's own content sources (mailbox, Drive, YouTube channel, website) by upserting on a uid you choose, and handle the three-value status enum.

Raw markdown guide for AI
Guide contents

This endpoint connects one of your customer's own content sources: their mailbox, their Drive, their YouTube channel, another website. It is driven from your product, over the API. There is no Context Link screen for your customer to visit.

Sources are addressed by a uid you choose, not by type, because one customer can hold several of the same kind (two mailboxes, three channels). The uid is your own word for the source. The write verb is a PUT upsert, so a retried request is always safe.

Request fields

uidstring
Required, in the path. The customer id you provisioned the account with. An unknown uid is a 404.
connection_uidstring
Required, in the path. The uid you choose for this source: a-z, 0-9, hyphen, underscore or dot, 1 to 255 characters, unique per customer. It is the address for every later call on this connection.
connection_typestring
Required, in the body. Which kind of source this is. The accepted values and the setup fields each one needs are in the table below.

You choose which types your organisation can offer, on the Connection types screen. A type you have not turned on is a 403 connection_type_not_activated. An OAuth type other than Google Drive turned on without your own OAuth keys is a 409 partner_credentials_required, on this call and on re-authorising, until you add them there.

Setup fields by type

Every type takes connection_type plus the fields below.

connection_type Required fields Authorisation
site site_domain (e.g. https://acme.com) None. Connects directly, one website per customer.
email email_address, imap_password, imap_server; optional imap_port (defaults to 993) None. Credentials are checked on the first sync.
youtube handle (e.g. @acmecorp) None. The handle is resolved to a channel before the connection is created.
monday api_token (pasted by the customer); optional workspace_id None. The token is resolved to a workspace before the connection is created. If it can see more than one workspace, send workspace_id.
webmention brand_name, web_domain None. Web Mentions of the brand across search and news.
google_doc return_url Redirect. Google consent screen. Indexes the whole of the customer's My Drive. There is no folder to choose, because you never see inside it.
one_drive return_url Redirect. Microsoft consent screen.
notion return_url Redirect. Notion consent screen.
basecamp return_url, project_url (e.g. https://3.basecamp.com/1234567/projects/9876543) Redirect. Basecamp consent screen. One project per connection. The project has to belong to the account the customer authorises, or the connection comes back auth_failed.

A missing or invalid field is a 422 carrying a per-field errors object, so you can put the message next to the input the customer filled in:

Mail connections default to the INBOX folder. Everything a customer pushes through the Custom Connections API is unaffected by any of this.

Response fields

Every successful call returns a single connection object.

Field Type Description
connection object The connection that was created or replayed.
connection.id integer Context Link's own id for the connection. You address it by the uid you chose, so you never need to store this.
connection.uid string The uid you chose for this source, echoed back.
connection.connection_type string The type, in the same form you sent it (google_doc, youtube).
connection.name string The type's own display name, such as GoogleDoc or Youtube. Never something you supply.
connection.status string Where the connection has got to: redirect_required, pending or connected. This is the value to branch on, and it is covered below.
connection.auth_status string pending_auth, authorised, auth_failed or disconnected. A type that needs no consent screen is authorised from the moment it is created.
connection.sync_status string unsynced, syncing, synced or error_syncing. A connection that has not yet attempted a sync is unsynced.
connection.redirect_url string The consent-screen URL to send the customer to. Present only when status is redirect_required. On any other status the key is left out of the response rather than returned as null.
connection.expires_at timestamp When that redirect_url stops working, 15 minutes after it was minted. Present only alongside redirect_url, on the same terms.

Two mailboxes on one customer are told apart by their uid. That is your own label, and the only one your customer will recognise.

Branch on status, not on redirect_url

Every response carries one status discriminator with three values. Branching on "is redirect_url present" mishandles the third.

status What it means What to do
redirect_required The type needs the customer's consent at the provider. redirect_url and expires_at are present. Send the customer's browser to redirect_url before expires_at.
pending Connected and authorised, first sync still running. Nothing. Wait for the connection.authorised webhook or poll.
connected Authorised and synced at least once. Query it.

201 on create, 200 on a replay of the same uid. A replay ignores body drift, exactly like POST /api_accounts. There is one exception. Changing the connection_type of a live uid is a 409 connection_type_immutable, because the content already indexed under it would be meaningless as another type. Delete and recreate instead.

A replay of a connection still in pending_auth re-mints a fresh redirect_url, because the usual reason you are retrying is that the customer abandoned the first consent screen.

The redirect flow

For the four OAuth types the customer has to say yes at the provider, so the flow is a browser round trip that starts and ends in your product:

  1. You PUT the connection with a return_url. You get back status: "redirect_required" and a redirect_url.
  2. You send the customer's browser to redirect_url. They consent at Google / Microsoft / Notion / Basecamp, under your brand and using your own OAuth client.
  3. The provider returns them to Context Link, which exchanges the code and redirects the browser to your return_url with ?connection_status=connected or ?connection_status=failed appended. Your existing query string is preserved.
  4. The authoritative record is the connection.authorised or connection.auth_failed webhook, which fires whatever the browser does.

return_url is required for these types, and it must be a publicly routable http(s) URL. The same host rules apply as for a webhook target. A private or loopback address is a 422 at request time.

The redirect_url is signed and expires 15 minutes after it is minted. An expired or tampered link shows the customer a plain "this link has expired, start again" page rather than bouncing them anywhere. At that point nothing proves where they came from.

Provider verification is yours to obtain. The consent screen shows your brand because it is your OAuth client. That also means the provider's unverified-app caps and review processes apply to you: Google restricts Gmail and Drive scopes behind an annual third-party security assessment, and an unverified client is limited to a small number of users. Start that process before you launch the type to your fleet.

Re-authorising a dead connection

Refresh tokens die: the customer changes their password, revokes access at the provider, or the grant simply expires. That sets auth_status: "auth_failed" and fires connection.auth_failed. Nothing is deleted. The indexed content stays, because the usual cause is transient. Re-authorising should not mean re-crawling from nothing.

You get a fresh redirect_url to send the customer to. Pass a return_url to override the one stored at create time. On a type that has no authorisation to renew this is a 422 connection_type_not_reauthorisable.

Limits

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
Posts per sync per connection 500 by default; lower where a sync is expensive: 30 for YouTube, 50 for Web Mentions
Write rate limit 5 per 10s per token and per organisation

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.

A customer's memory connection is the one exception: it never counts toward the 10, and it has no cap of its own to worry about.