Skip to main content

Start an HTTP connector

Building a connector, step 7 (HTTP track, 1 of 5). Previous: Choose a kind.

An HTTP connector is a manifest.json that declares everything about the connector, plus one small TypeScript module per operation, called a handler. There is no class to write: Owlie's HTTP engine reads the manifest and calls your handlers. Write the manifest first, from the design you made in steps 3 to 5. Every handler you write afterwards is typed from it.

The files​

A connector is a set of files. The Connector Builder shows them as a file tree. An export carries the same content as one JSON document: the manifest under its own key, and every other file keyed by its path (Pack format).

manifest.json the declaration
handlers/connection/validateConfig.ts
handlers/connection/testConnection.ts
handlers/user/fetchOne.ts one module per operation: handlers/<entity>/<operation>.ts
handlers/user/fetchAll.ts
handlers/team/fetchRelationships.ts
handlers/grants/team_member/add.ts one add.ts and remove.ts per writable Grant kind
handlers/grants/team_member/remove.ts
lib/ shared modules your handlers import, and optional hooks
fixtures/inputs.json saved test inputs for the Test panel
README.md your design notes: vendor facts, assumptions, the Grant kind table
CHANGELOG.md what changed, newest dated entry first

Owlie generates types.gen.ts from the manifest when it builds your connector. Handlers import their types from it as @connector/types, which reads the same from every folder (the relative path works too: ../../types.gen.ts from a handler, ../../../types.gen.ts from a Grant handler). It is never part of an export, and you never edit it. Files under lib/ import the same way, as @connector/lib/<file>.ts.

Create the connector​

In the Connector Builder​

  1. Open Admin > Integrations > Connectors and select the Custom tab.
  2. Select New connector.
  3. Under Start from, choose Blank. (A connector export imports a pack instead.)
  4. Under Kind, choose HTTP.
  5. Enter a Name. Owlie fills in the Key from it; change the key now if you want another, since it cannot change later.
  6. Select Create connector.

The builder opens on the draft. Its tabs (Basics, Config variables, Auth, Entities, Grant kinds, Files) edit the manifest through forms, and Files shows every file. The builder saves as you type; there is no save button.

Through the API​

Create the connector with createCustomConnector ({ "key": "acme-projects", "name": "Acme Projects", "kind": "http" }), then write its manifest and files into the draft with updateCustomConnectorDraft. Or build the whole connector locally and import it in one call with customConnectorImport. Build with the API and agents lists the operations and their inputs.

Write the manifest​

The manifest is JSON. This one declares a connector for a fictional project-management system, Acme Projects, with users and teams:

{
"key": "acme-projects",
"version": 1,
"name": "Acme Projects",
"description": "Acme Projects users and teams, synced and provisioned.",
"icon": "@acmeprojects.example",
"kind": "http",
"provides": ["sync", "provision"],
"pagination_type": "cursor",
"config": {
"schema": {
"type": "object",
"required": ["subdomain"],
"properties": {
"subdomain": { "type": "string", "minLength": 1, "title": "Subdomain", "x-suffix": ".acmeprojects.example" }
},
"additionalProperties": false
}
},
"auth": [],
"entities": {},
"grant_kinds": []
}
FieldWhat to put there
keyLowercase letters, digits, - and _, starting with a letter or digit. It identifies the connector and cannot change.
versionThe major version, 1 for a new connector.
name, description, iconWhat the catalog shows. icon is @ plus the vendor's domain, or an https:// image URL.
kindhttp.
providessync if it reads, plus provision if it creates accounts or writes Grants.
pagination_typeThe default paging style for list calls: cursor, next-token, offset-limit, page-number or link-header.
configThe settings an install fills in besides credentials, as JSON Schema.
authHow it signs in. The next page covers it.
entitiesThe entities from step 3, each with its record schema.
grant_kindsThe Grant kinds from step 4.
custom_opsExtra actions workflows and agents can call, if you have any.

Every field, including the optional ones, is in Connector manifest.

Declare the entities​

Each entity has a name, a JSON Schema for its record, its identifiers, and whether it is the account. Here is the account entity for Acme Projects:

{
"user": {
"name": "User",
"is_account": true,
"identifier_paths": ["id", "email"],
"sync_support": { "supports_incremental": false, "supports_deleted": false },
"schema": {
"type": "object",
"properties": {
"id": { "type": "string", "readOnly": true, "x-identifier": true, "x-provider-stable-id": true },
"email": {
"type": "string",
"format": "email",
"x-identifier": true,
"x-provisioning": { "requiredOn": ["PROVISION"] }
},
"first_name": { "type": "string" },
"last_name": { "type": "string" },
"status": { "type": "string", "enum": ["active", "deactivated"], "readOnly": true }
}
},
"sync_profile": {
"target": "RESOURCE",
"matchingRules": [{ "identityField": "email", "externalExpression": "email" }],
"is_active": "status != 'deactivated'"
}
}
}

sync_profile sets the defaults for the install's account sync:

  • "target": "RESOURCE" is for a system people are given access to. Sync links each account to an existing Owlie identity through matchingRules (here, the identity's email equals the record's email) and flags an account that matches nobody. IDENTITY is only for a source of people, such as an HR system: Sync then creates an identity for every account it cannot match. Without a target, Owlie treats the connector as an identity source, so always declare it.
  • is_active is an expression over the record's own properties that tells Sync whether the account is active (Expressions). Without it, Sync cannot tell an active account from a deactivated one.

The account also gets a provisioning profile, covered on Write handlers.

The handlers your manifest requires​

Your manifest decides which handlers must exist. Publishing refuses a connector that lacks one:

HandlerRequired when
connection.testConnectionAlways
<entity>.fetchOneFor every entity, including lookup entities
<entity>.fetchAllFor every entity, when provides includes sync
<entity>.fetchAllSinceFor an entity with sync_support.supports_incremental: true
<entity>.fetchRelationshipsOn the discovered_via entity of every per-entity Grant kind
<account entity>.createWhen provides includes provision, unless the account's create_semantics is external
grant.<kind>.add and grant.<kind>.removeFor every writable Grant kind

connection.validateConfig is optional: without it, Owlie checks the install against your configuration schemas. Every other handler is optional, and an operation you leave out is simply not available. A handler for something the manifest does not declare (an undeclared entity, a read-only Grant kind, a custom operation missing from custom_ops) is refused.

What Owlie checks​

A draft can be incomplete while you work: you can test an add handler before its remove exists. When you import or publish, Owlie checks the manifest and your files together. It refuses, for example, a handler for an entity that does not exist, a writable Grant kind missing its add or remove handler, a Grant kind that names an undeclared entity, and a secret written into the manifest. Each problem has a code and a message; Validation issues explains every code and how to fix it.

Next: Authentication and configuration