Developers
Manifest Reference
Complete specification for plugin manifest files.
Overview
The manifest is a JSON file that describes your plugin — its identity, tools, and authentication requirements. The platform reads this file to understand what your plugin does and how to interact with it.
Full manifest structure
{
"slug": "MY_PLUGIN",
"version": "1.0.0",
"name": "My Plugin",
"description": "What this plugin does",
"author": {
"name": "Your Name",
"email": "you@example.com",
"url": "https://yoursite.com"
},
"tags": ["crm", "sales"],
"homepage": "https://yoursite.com/plugin",
"baseUrl": "https://api.yourservice.com",
"auth": { "type": "none" },
"tools": [],
"configurationSchema": {}
}Fields
Required fields
| Field | Type | Description |
|---|---|---|
slug | string | Unique uppercase identifier for your plugin (e.g., ACME_CRM). Must be unique across all plugins. |
version | string | Semantic version number (e.g., 1.0.0, 2.1.3). |
name | string | Human-readable name shown in the UI. |
baseUrl | string | The base URL of your plugin's HTTP endpoint. Tool calls are sent here. |
tools | array | List of tools your plugin provides. See below. |
auth | object | Authentication configuration. See below. |
Optional fields
| Field | Type | Description |
|---|---|---|
description | string | Brief description of what the plugin does. Shown to users during installation. |
author | object | Author info: name, email, and url. |
tags | string[] | Categories for discoverability (e.g., ["payments", "finance"]). |
homepage | string | Link to your plugin's documentation or website. |
configurationSchema | object | JSON Schema defining installation-time configuration options. |
Tools
Each tool represents an action the AI agent can perform. Define them in the tools array.
{
"name": "lookup_customer",
"description": "Look up a customer by their phone number or email. Use this when the agent needs customer information.",
"inputSchema": {
"type": "object",
"properties": {
"phone": {
"type": "string",
"description": "Customer phone number (with country code)"
},
"email": {
"type": "string",
"description": "Customer email address"
}
},
"required": ["phone"]
},
"outputSchema": {
"type": "object",
"properties": {
"name": { "type": "string" },
"status": { "type": "string" }
}
},
"endpoint": {
"method": "POST",
"path": "/execute"
}
}Tool fields
| Field | Type | Required | Description |
|---|---|---|---|
name | string | Yes | Unique name for the tool within this plugin. |
description | string | Yes | Describes what the tool does and when to use it. The AI reads this to decide when to call the tool. Write it clearly. |
inputSchema | object | Yes | JSON Schema describing the input parameters. The AI uses this to know what data to send. |
outputSchema | object | No | JSON Schema describing the expected response format. |
endpoint.method | string | No | HTTP method (POST or GET). Defaults to POST. |
endpoint.path | string | No | URL path appended to baseUrl. Defaults to /execute. |
metadata | object | No | Arbitrary key-value metadata for your own use. |
Writing good tool descriptions
The AI agent uses the description field to decide when to call your tool. Be specific:
Good: "Look up the shipping status of an order by its tracking number. Call this when a customer asks where their package is or wants a tracking update."
Bad: "Get shipping info."
The better your description, the more accurately the agent will use your tool.
Authentication types
No authentication
{ "type": "none" }Your endpoint receives requests without any authentication. The platform still includes a signed platform token in the Authorization header that you can verify (see Authentication).
Secret (Platform Token)
{ "type": "secret" }Every request includes a signed platform token in the Authorization header. Your endpoint should verify this token to confirm the request came from the platform.
OAuth 2.0
{
"type": "oauth2",
"authorizationUrl": "https://provider.com/authorize",
"tokenUrl": "https://provider.com/token",
"scope": ["read", "write"]
}For plugins that need to access user accounts on external services. The platform handles the full OAuth flow — redirecting users to authorize, exchanging codes for tokens, and refreshing tokens automatically.
When your tool is called, the user's access token is included in the request context. See Authentication for the full OAuth flow.
Configuration schema
If your plugin needs configuration at install time (e.g., an API key, a workspace URL), define it with configurationSchema:
{
"configurationSchema": {
"type": "object",
"properties": {
"workspace_url": {
"type": "string",
"description": "Your workspace URL"
},
"api_key": {
"type": "string",
"description": "Your API key"
}
},
"required": ["workspace_url"]
}
}When an organization installs your plugin, they'll be asked to fill in these configuration values. The values are included in the context.config object on every tool call.
Request format
When the agent calls one of your tools, the platform sends a POST request to your endpoint:
URL: {baseUrl}{tool.endpoint.path} (defaults to {baseUrl}/execute)
Headers:
Authorization: Bearer {platform_token}— Signed token for verificationContent-Type: application/jsonX-User-Access-Token: {oauth_token}— Only present if OAuth is configured and the user has authorized
Body:
{
"tool": "lookup_customer",
"input": {
"phone": "+254700000000"
},
"context": {
"organizationId": "org_abc123",
"instanceId": "inst_xyz789",
"user": {
"id": "hashed_identifier",
"hashVersion": 1
},
"config": {
"workspace_url": "https://myworkspace.example.com"
},
"userAccessToken": "eyJhbG..."
}
}Context fields
| Field | Description |
|---|---|
organizationId | The organization that installed your plugin |
instanceId | The specific WhatsApp instance making the call |
user.id | A hashed identifier for the WhatsApp user (never the actual phone number) |
config | Configuration values set during plugin installation |
userAccessToken | The user's OAuth access token (only if OAuth is configured) |
Response format
Return a JSON response with your result. The agent will use the data to continue the conversation.
{
"name": "John Doe",
"status": "active",
"lastOrder": "2024-01-15"
}There's no required structure — return whatever makes sense for your tool. The agent will interpret the response based on the tool's description and context.
For errors, return an appropriate HTTP status code and an error message:
{
"error": "Customer not found"
}Next steps
- Authentication — Verify platform tokens and implement OAuth
- Testing & Debugging — Test your plugin in sandbox mode