Agix pulls live data from external services — Stripe, Salesforce, HubSpot, Google Analytics, Notion, Airtable, and SQL — through a unified connector layer. Every connector implements the sameDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/manusapis/Agix/llms.txt
Use this file to discover all available pages before exploring further.
IConnector interface and is registered in a central map in connector.factory.ts. Adding a new data source follows the same three-step pattern for every service you want to support.
The IConnector contract
The interface is defined in src/services/connectors/base.connector.ts:
BaseConnector provides a concrete isConnected() — it returns true when this.config is not null — and stores the ConnectorConfig in a protected config field. Concrete classes inherit both and only need to implement connect(), disconnect(), and sync().
The connector registry in
connector.factory.ts is a plain Map. Adding a
new entry to that map is all that is needed to make the connector available
throughout the application. No other files need to be modified — the
getSupportedConnectors() function reads directly from the map’s keys, and
the UI enumerates that list dynamically.Steps
Open
src/types/connector.types.ts and append your connector’s identifier to the ConnectorType union. This string is used as the map key in the registry and as the type field in every ConnectorConfig, SyncRequest, and SyncResult related to your service.// src/types/connector.types.ts
export type ConnectorType =
| "stripe"
| "salesforce"
| "hubspot"
| "google-analytics"
| "notion"
| "airtable"
| "sql"
| "shopify"; // ← add your new type here
Create a new file at
src/services/connectors/shopify.connector.ts. Pass your type string to super(), store the config in connect(), clear it in disconnect(), and implement sync() to fetch the requested resource from the external API.// src/services/connectors/shopify.connector.ts
import { BaseConnector } from "./base.connector";
import type { ConnectorConfig, SyncRequest, SyncResult } from "@/types/connector.types";
export class ShopifyConnector extends BaseConnector {
constructor() {
super("shopify");
}
async connect(config: ConnectorConfig): Promise<boolean> {
this.config = config;
return true;
}
async disconnect(): Promise<void> {
this.config = null;
}
async sync(request: SyncRequest): Promise<SyncResult> {
const res = await fetch(
`https://${this.config?.credentials.shop}.myshopify.com/admin/api/2024-01/${request.resource}.json`,
{
headers: {
"X-Shopify-Access-Token": this.config?.credentials.accessToken ?? "",
},
}
);
if (!res.ok) {
throw new Error(`Shopify sync failed: ${res.status} ${await res.text()}`);
}
const data = await res.json();
return {
connector: "shopify",
resource: request.resource,
syncedAt: new Date().toISOString(),
rowsInserted: data[request.resource]?.length ?? 0,
rowsUpdated: 0,
};
}
}
The
SyncResult shape — connector, resource, syncedAt, rowsInserted, and rowsUpdated — is required. The connector factory and the data service both destructure these fields when writing rows back into the spreadsheet.Open
src/services/connectors/connector.factory.ts, import your class, and add one entry to the registry map:// src/services/connectors/connector.factory.ts
import { ShopifyConnector } from "./shopify.connector";
const registry = new Map<ConnectorType, () => IConnector>([
["stripe", () => new StripeConnector()],
["salesforce", () => new SalesforceConnector()],
["hubspot", () => new HubSpotConnector()],
["google-analytics", () => new GoogleAnalyticsConnector()],
["notion", () => new NotionConnector()],
["airtable", () => new AirtableConnector()],
["sql", () => new SQLConnector()],
["shopify", () => new ShopifyConnector()], // ← new entry
]);
The existing StripeConnector as a reference
The Stripe connector is the simplest shipped implementation and a good template:
IConnector methods, StripeConnector also exposes domain-specific public methods (pullSubscriptions(), pullPaymentHistory(), pullCustomers()) that the data service calls directly. You can do the same for any resource-specific operations that do not fit naturally into the generic sync() signature.
Connector config and credentials
When the user authenticates a connector in the sidebar, the UI assembles aConnectorConfig and passes it to connector.connect(config). The shape of credentials is a free-form Record<string, string>, so each connector declares its own expected keys by convention:
Files changed summary
| File | Change |
|---|---|
src/types/connector.types.ts | Add the new ID to the ConnectorType union |
src/services/connectors/<name>.connector.ts | New file — extends BaseConnector |
src/services/connectors/connector.factory.ts | One new entry in the registry map |