Connector

A Connector is a catalog entry that describes one integration point Well supports — a source of data to pull in (direction=input) or a destination to push data out to (direction=output). The catalog is seeded centrally and workspace-agnostic: it defines the provider, auth flow, transport, and which Well entity models a sync can populate, but carries no per-workspace credentials or state. Workspace-level activation and OAuth tokens live on the WorkspaceConnector join entity. A Connector is referenced by WorkspaceConnector (per-workspace activation), ConnectorFilter (routing rules), and ProviderConnector (blueprint-provider pairings).

NamingValue
ObjectConnector
Resource type (JSON:API type)connector
Collection / records rootconnectors
REST base/v1/connectors
Entity classConnector

API operations

OperationMethod & pathStatus
ListGET /v1/connectors✅ Implemented
RetrieveGET /v1/connectors/{id}✅ Implemented
CreatePOST /v1/connectors✅ Implemented
UpdatePATCH /v1/connectors/{id}✅ Implemented
DeleteDELETE /v1/connectors/{id}✅ Implemented

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
connector_idstring, UUID, 🔒 system✅ Yesunique; generated by gen_random_uuid() at INSERTPublic stable identifier for the connector. Used in all API and client references. Internal pk is never exposed.
namestring✅ YesHuman-readable display name of the integration (e.g. "Stripe", "Notion", "Gmail"). Shown in the connector marketplace UI.
providerenum (ProviderTypeEnum)✅ Yesnative PostgreSQL enum provider_type_enumapideck | chift | well | plaid_eu | plaid_usRouting key that determines which backend provider adapter handles sync orchestration for this connector. well = first-party or MCP-based integration; apideck / chift = third-party aggregator proxies; plaid_eu / plaid_us = Plaid Open Banking (region-split).
category_idstring✅ YesLogical category used for UI grouping in the connector marketplace (e.g. "finance", "crm", "productivity", "email", "file-storage", "messaging", "api", "internal"). Rendered via the connector_category display type.
service_idstring✅ YesProvider-scoped service identifier that uniquely names the integration within its provider routing layer (e.g. "stripe", "google-drive", "qonto"). For Apideck connectors this matches the Apideck service_id. Used as the enum value in CreateConnectorBody and in URL slugs. Rendered via the unique_key display type.
external_connector_idstring⚪ NonullableOpaque identifier assigned by the external provider system (e.g. Apideck's internal connector ID). Null for first-party and MCP-based connectors.
slugstring⚪ NonullableURL-safe human-readable short name used as the MCP provider slug (e.g. "stripe", "pennylane", "wise"). Routes requests through apps/api/src/mcps/<slug>/. Null for connectors without a dedicated MCP shim.
statusenum (StatusTypeEnum)✅ Yesnative PostgreSQL enum status_type_enum; default unavailable; partial index idx_connectors_status_created_at covers (status, created_at DESC) WHERE deleted_at IS NULLavailable | coming_soon | unavailable | maintenanceAvailability state of the connector in the marketplace. available = fully operational and connectable; coming_soon = announced but not yet connectable; unavailable = disabled; maintenance = temporarily suspended. Rendered via the status_badge display type.
directionenum (DirectionEnum)✅ Yesnative PostgreSQL enum direction_enum; default input; compound index idx_connectors_direction_status on (direction, status)input | outputData-flow direction. input = the connector is a source that pulls external data into Well (e.g. Stripe, Gmail, bank feeds). output = the connector is a router that pushes Well data to an external system (e.g. Pennylane, QuickBooks, Webhook). Rendered via the connector_direction display type.
authorization_flowenum (AuthorizationFlowEnum)✅ Yesnative PostgreSQL enum authorization_flow_enum; default nonenone | redirect | oauth-manual | oauth-dcr | oauth-cimd | api-key | external-api-key | wsseAuthentication mechanism used to connect a workspace to this connector. none = no auth needed; redirect = simple OAuth redirect; oauth-manual = OAuth without .well-known discovery (endpoints declared in auth_config.oauth_config); oauth-dcr = OAuth with .well-known Dynamic Client Registration (RFC 7591); oauth-cimd = client-initiated mode; api-key = Well-managed API key; external-api-key = user-supplied API key; wsse = WS-Security UsernameToken (iBanFirst).
transportenum (TransportEnum)✅ Yesnative PostgreSQL enum transport_enum; default apimcp | apiWire transport used during sync. mcp = sync runs over the MCP protocol (SSE or StreamableHTTP) via apps/api/src/mcps/<slug>/; api = sync uses a direct HTTP REST/GraphQL API call via provider-specific adapter code.
auth_configjsonb (ConnectorAuthConfig)⚪ NonullableProtocol-level auth metadata for the connector (template, not per-workspace). Fields: oauth_metadata_url (string) — .well-known discovery URL for OAuth DCR; authorization_endpoint (string) — override authorization URL; oauth_config (object: {authorization_endpoint, token_endpoint, scopes?}) — manual OAuth endpoints when .well-known is unavailable; mcp_server_url (string) — base URL of the provider's MCP server; token_test_url (string) — URL polled to verify token validity. Per-workspace credentials (client_id, client_secret, access_token, refresh_token) are stored in WorkspaceConnector.config, never here.
supported_target_modelsjsonb (string[])⚪ NonullableList of Well entity model names this connector can populate during a sync. Drives the sync orchestrator's target selection. Known values from the 12-model catalog: company, people, invoice, transaction, account, ledger_account, journal, journal_entry, email, payment_means, invoice_transaction, document. Null or empty for output-only connectors or connectors without MCP sync.
created_atdatetime, 🔒 system✅ Yesset on INSERT via MikroORM onCreate lifecycle hook; default new Date()Timestamp when the connector catalog entry was first created. Included in the hot-path partial index idx_connectors_status_created_at for marketplace list queries.
updated_atdatetime, 🔒 system⚪ Noset on INSERT and UPDATE via MikroORM onCreate/onUpdate lifecycle hooksTimestamp of the last modification to the catalog entry (status change, auth_config update, new target model added).
deleted_atdatetime⚪ Nonullable; soft-delete sentinel; the partial index idx_connectors_status_created_at filters WHERE deleted_at IS NULLSoft-delete timestamp. When set, the connector is logically removed from the catalog. All live queries must filter deleted_at IS NULL. A non-null value should trigger removal of associated WorkspaceConnector activations.

Relationships

NameTypeRequiredDescription
workspace_connectorsto-many (WorkspaceConnector)⚪ NoAll per-workspace activations of this connector. Each WorkspaceConnector row represents one workspace's live (or disconnected) instance of this Connector, carrying its OAuth tokens, sync status, and config. The inverse of WorkspaceConnector.connector (ManyToOne). Not declared as @OneToMany on Connector itself — traversed via WorkspaceConnectorRepository.
connector_filtersto-many (ConnectorFilter)⚪ NoRouting filters associated with this connector. Two kinds: template filters (template=true, workspace=null — shared defaults for all workspaces) and custom filters (template=false, workspace set — per-workspace overrides). Filters carry a JSONB config (Hasura WHERE clause syntax) and a natural_language description for the UI. The inverse of ConnectorFilter.connector.
provider_connectorto-one (ProviderConnector)⚪ NoThe ProviderConnector join record that pairs this connector with a Provider (blueprint-based document-capture provider). The unique constraint on ProviderConnector.connector means at most one Provider is linked per Connector. Null for connectors not linked to any Provider blueprint.

System-computed

  • connector_id is generated by PostgreSQL gen_random_uuid() at INSERT time via MikroORM defaultRaw. It is unique and immutable after creation.
  • created_at is set to new Date() on INSERT via the MikroORM @Property({ onCreate }) lifecycle hook. Never updated after creation.
  • updated_at is set to new Date() on both INSERT and UPDATE via MikroORM @Property({ onCreate, onUpdate }) hooks. Reflects the last catalog modification.
  • deleted_at is null by default (no MikroORM onDelete lifecycle — soft-delete is performed by setting the field explicitly in the service layer). All list queries must apply a WHERE deleted_at IS NULL predicate. The partial index idx_connectors_status_created_at only covers rows WHERE deleted_at IS NULL.
  • The Connector catalog is seeded centrally via apps/api/src/database/seed.ts (143 entries as of Q2 2026, 92 of which use transport=mcp). Connector rows are workspace-agnostic — they carry no per-workspace state. Per-workspace auth tokens and sync configuration live exclusively on WorkspaceConnector.config.
  • status defaults to unavailable at the database level (StatusTypeEnum.UNAVAILABLE). The seed overrides most live integrations to available; connectors under development ship as coming_soon.
  • direction defaults to input at the database level (DirectionEnum.INPUT).
  • authorization_flow defaults to none at the database level (AuthorizationFlowEnum.NONE).
  • transport defaults to api at the database level (TransportEnum.API).
  • auth_config.mcp_server_url is the MCP entry point URL for transport=mcp connectors. Per-workspace client_id, client_secret, access_token, refresh_token, and dcr_access_token are stored in WorkspaceConnector.config, never in auth_config.
  • slug, when set, is the key into apps/api/src/mcps/<slug>/ for per-provider GENERATED shim files (config.ts, tools.json, connector-seed.ts). These generated files must not be hand-edited — the source of truth is packages/mcp-generator/configs/<slug>.yaml.
  • supported_target_models drives the sync orchestrator's target model selection. Valid values from the 12-model catalog: company, people, invoice, transaction, account, ledger_account, journal, journal_entry, email, payment_means, invoice_transaction, document.
  • Three compound indexes exist on the connectors table: idx_connectors_status on (status); idx_connectors_direction_status on (direction, status); idx_connectors_status_created_at partial index on (status, created_at DESC) WHERE deleted_at IS NULL — optimised for the hot-path connector marketplace list query.

Example

{
  "data": {
    "type": "connector",
    "id": "a1b2c3d4-e5f6-4a8b-9c0d-454545000001",
    "attributes": {
      "connector_id": "a1b2c3d4-e5f6-4a8b-9c0d-454545000001",
      "name": "Stripe",
      "provider": "well",
      "category_id": "finance",
      "service_id": "stripe",
      "external_connector_id": null,
      "slug": "stripe",
      "status": "available",
      "direction": "input",
      "authorization_flow": "oauth-dcr",
      "transport": "mcp",
      "auth_config": {
        "oauth_metadata_url": "https://mcp.stripe.com/.well-known/oauth-authorization-server",
        "mcp_server_url": "https://mcp.stripe.com"
      },
      "supported_target_models": [
        "company",
        "people",
        "invoice",
        "transaction",
        "account",
        "ledger_account",
        "payment_means",
        "invoice_transaction"
      ],
      "created_at": "2025-09-01T08:00:00.000Z",
      "updated_at": "2026-03-15T10:22:00.000Z",
      "deleted_at": null
    }
  }
}
Source: apps/api/src/database/entities/Connector.ts · domain: ingestion · tier: Main