# Plugin API (/docs/reference/plugin-api)



## FlowlibPlugin [#flowlibplugin]

```ts
interface FlowlibPlugin {
  id: string;
  name?: string;

  // Lifecycle
  init?: (ctx: FlowlibPluginContext) => Promise<FlowlibPluginInitResult | void>;
  shutdown?: () => Promise<void> | void;

  // Extensions
  actions?: ActionDefinition[];
  schema?: FlowlibPluginSchema;
  requiredTables?: string[];
  endpoints?: FlowlibPluginEndpoint[];
  hooks?: FlowlibPluginHooks;

  // Metadata
  setupInstructions?: string;
  $ERROR_CODES?: Record<string, { message: string; statusCode: number }>;
}
```

## FlowlibPluginContext [#flowlibplugincontext]

Passed to `init()`:

```ts
interface FlowlibPluginContext {
  db: DatabaseConnection;
  dbType: DatabaseType;
  logger: Logger;
  registerTool: (def: AgentToolDefinition, executor: AgentToolExecutor) => void;
  config: FlowlibConfig;
}
```

## FlowlibPluginHooks [#flowlibpluginhooks]

```ts
interface FlowlibPluginHooks {
  beforeFlowRun?: (ctx: FlowRunHookContext) => Promise<{ cancel?: boolean; inputs?: any } | void>;
  afterFlowRun?: (ctx: FlowRunHookContext) => Promise<void>;
  beforeNodeExecute?: (
    ctx: NodeExecuteHookContext,
  ) => Promise<{ skip?: boolean; params?: any } | void>;
  afterNodeExecute?: (ctx: NodeExecuteHookContext) => Promise<{ output?: any } | void>;
  onRequest?: (ctx: RequestHookContext) => Promise<{ response?: any; request?: any } | void>;
  onResponse?: (ctx: ResponseHookContext) => Promise<{ response?: any } | void>;
  onAuthorize?: (ctx: AuthorizeHookContext) => Promise<{ allowed?: boolean } | void>;
}
```

### Hook behaviour [#hook-behaviour]

| Hook                | Can short-circuit?         | Return to modify              |
| ------------------- | -------------------------- | ----------------------------- |
| `beforeFlowRun`     | Yes (`{ cancel: true }`)   | `{ inputs }` to modify inputs |
| `afterFlowRun`      | No                         | —                             |
| `beforeNodeExecute` | Yes (`{ skip: true }`)     | `{ params }` to override      |
| `afterNodeExecute`  | No                         | `{ output }` to override      |
| `onRequest`         | Yes (`{ response }`)       | `{ request }` to modify       |
| `onResponse`        | No                         | `{ response }` to replace     |
| `onAuthorize`       | Yes (`{ allowed: false }`) | `{ allowed: true }` to allow  |

## FlowlibPluginEndpoint [#flowlibpluginendpoint]

```ts
interface FlowlibPluginEndpoint {
  method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
  path: string;
  handler: (context: PluginEndpointContext) => Promise<PluginEndpointResponse>;
  permission?: FlowlibPermission;
  isPublic?: boolean;
}
```

Endpoints are mounted at `/plugins/{pluginId}{path}`.

## PluginEndpointContext [#pluginendpointcontext]

```ts
interface PluginEndpointContext {
  body: Record<string, unknown>;
  params: Record<string, string>;
  query: Record<string, string | undefined>;
  headers: Record<string, string | undefined>;
  identity: FlowlibIdentity | null;
  database: PluginDatabaseApi;
  request: Request;
  core: PluginEndpointCoreApi;
  getFlowlib: () => FlowlibInstance;
}
```

## PluginEndpointResponse [#pluginendpointresponse]

```ts
type PluginEndpointResponse =
  | { status?: number; body: unknown } // JSON response
  | { status?: number; stream: ReadableStream } // Streaming response
  | Response; // Raw Web API Response
```

## FlowlibPluginSchema [#flowlibpluginschema]

```ts
type FlowlibPluginSchema = Record<
  string,
  {
    fields: Record<
      string,
      {
        type: 'string' | 'number' | 'boolean' | 'text' | 'json';
        primaryKey?: boolean;
        required?: boolean;
        unique?: boolean;
        default?: any;
        references?: { table: string; field: string };
      }
    >;
  }
>;
```

## FlowlibFrontendPlugin [#flowlibfrontendplugin]

```ts
interface FlowlibFrontendPlugin {
  id: string;
  name?: string;
  sidebar?: PluginSidebarContribution[];
  routes?: PluginRouteContribution[];
  panelTabs?: PluginPanelTabContribution[];
  headerActions?: PluginHeaderActionContribution[];
  components?: Record<string, ComponentType>;
  providers?: ComponentType<{ children: ReactNode }>[];
  apiHeaders?: () => Record<string, string>;
  checkPermission?: (permission: string, ctx?: any) => boolean | undefined;
}
```
