Skip to main content
Custom integrations allow you to extend Cargo’s capabilities by connecting to any external service or API. By building a custom integration server, you can create actions, data extractors, and autocomplete endpoints that seamlessly integrate with Cargo’s workflows.
Check out the dummy-integration repository for a complete working example of a custom integration.

Overview

A custom integration is an HTTP server that implements a specific API contract. Cargo communicates with your integration server to:
  • Fetch the manifest — Describes your integration’s capabilities (actions, extractors, autocompletes)
  • Authenticate connections — Validates user credentials when creating a connector
  • Execute actions — Performs operations in your external service
  • Fetch data — Pulls data from your service into Cargo data models
  • Provide autocomplete options — Powers dynamic dropdowns in the Cargo UI

Getting started

A custom integration can be hosted in two ways:
  • As a Cargo Hosting worker (recommended) — write the integration as an edge fetch(request, env) handler and let Cargo host it. No infra, no ngrok, no separate domain.
  • As an externally hosted server — a Node/Express (or any language) server you host yourself. Use this when you need a runtime that isn’t supported by workers, or you already have an existing server to wrap.

Step 1: Scaffold the worker

This drops a TypeScript worker (typed against @cargo-ai/worker-sdk) that already implements the Custom Integration HTTP contract:
Edit src/getManifest.ts (manifest), src/authenticate.ts (credential check), and the per-action / per-extractor handlers under src/. Add any external hosts you call to manifest.json#outboundAllowlist. Run npm run type:check to validate against the typed contract.

Step 2: Provision a worker slot, deploy, promote

The Cargo Hosting build pipeline runs npm ci + esbuild src/index.ts --bundle --format=esm --platform=neutral --target=es2022 (esbuild transpiles TypeScript natively) to produce the final edge bundle.

Step 3: Register the worker as a custom integration

Or declaratively with the CDK:
Cargo will fetch GET /manifest from your worker (cached for 5 minutes) and the integration will appear in your workspace’s connector catalog.
Use cargo-ai hosting worker init x --list-templates to see all available worker templates.

Option B — Self-hosted external server

Use this path when you can’t run on a worker (long-running compute, large native dependencies, an existing Express/Flask/Go service you want to expose, etc.).

Step 1: Create your integration server

Start by cloning the dummy integration repository:
Run the development server:
Your integration server will start on a local port (e.g., http://localhost:3000).

Step 2: Expose your local server with ngrok

During development, you can use ngrok to expose your local server to the internet:
This will give you a public URL like https://abc123.ngrok.io that you can use to register your integration with Cargo.
For production, deploy your integration server to a cloud provider (AWS, GCP, Vercel, Railway, etc.) and use that URL instead.

Step 3: Register the external server in Cargo

Or via raw HTTP:
Once registered, Cargo will fetch the manifest from your server and the integration will appear in your workspace’s connector catalog.
Your external integration server must be publicly accessible. Cargo’s backend needs to make HTTP requests to your server’s endpoints.

Cargo API for custom integrations

Manage your custom integrations using these API endpoints. All endpoints require authentication.

Create a custom integration

Request body — discriminated by kind:
Response:

List custom integrations

Response:

Get a custom integration

Response:

Update a custom integration

Request body — pass either baseUrl (for external integrations) or workerUuid (for worker integrations); the integration’s kind cannot change.

Delete a custom integration


Integration server API

Your integration server must implement the following HTTP endpoints:

GET /manifest

Returns the integration manifest describing all capabilities. Response:

POST /authenticate

Validates the connector configuration (credentials). Request body:
Response (success):
Response (error):

POST /listUsers

Lists users available in the connected service (optional). Request body:
Response:

POST /actions/[actionSlug]/execute

Executes an action. The actionSlug corresponds to a key in the actions object returned by your /manifest endpoint. Request body:
Response (completed):
Response (in progress):

POST /extractors/[extractorSlug]/fetch

Fetches data for a data model extractor. Request body:
Response:

POST /extractors/[extractor]/count

Returns the count of records for preview purposes. Response:

POST /autocompletes/[autocompleteSlug]

Provides options for dynamic dropdowns in the UI. Request body:
Response:

POST /dynamicSchemas/[schemaSlug]

Returns dynamic JSON schemas based on runtime parameters. Request body:
Response:

POST /completeOauth

Completes OAuth flow for integrations using OAuth authentication. Request body:
Response:

Using autocompletes in action/extractor forms

To power dynamic dropdowns in your action configuration forms, use the IntegrationAutocompleteWidget in your uiSchema. This widget calls your /autocompletes/{slug} endpoint to fetch options.

Basic usage

In your /manifest endpoint response, include an autocompletes entry and reference it in an action’s uiSchema:

Widget options

Dynamic parameters

You can reference other form values in params using special path expressions:
Path expressions: This allows cascading dropdowns where one field’s options depend on another field’s selected value.

Using dynamic schemas

For fields where the schema depends on runtime values (like user selections), use the DynamicSchemaWidget. This widget fetches the JSON schema from your /dynamicSchemas/{slug} endpoint.

Basic usage

In your /manifest endpoint response, include a dynamicSchemas entry and reference it in an action’s uiSchema:

Widget options

Endpoint response

Your /dynamicSchemas/{slug} endpoint should return both the JSON schema and UI schema for the field:
Dynamic schemas are useful when your integration has different fields per object type (e.g., CRM objects like Contacts vs Companies) or when fields are user-configurable.

Best practices

Validate inputs

Always validate connector and action configurations before processing requests.

Handle errors gracefully

Return meaningful error messages to help users troubleshoot issues.

Implement rate limiting

Define rate limits in your /manifest response to prevent overwhelming your service.

Use caching

Enable caching for autocomplete endpoints to improve performance.

Example integration

For a complete working example, see the Cargo Dummy Integration repository on GitHub. The repository includes:
  • Full project structure with TypeScript
  • Example /manifest endpoint with actions and extractors
  • Authentication endpoint implementation
  • Action execution handlers
  • Development and build scripts