Capabilities & Webhooks
Configure native business actions that AI agents can execute on behalf of your customers.
What is a Capability? A capability is a business action (booking, contact, catalog search...) that AI agents can discover and execute. Unlike connectors which integrate with external services, capabilities are fully controlled by your business through webhooks.
Capabilities vs Connectors
| Feature | Capabilities | Connectors |
|---|---|---|
| Control | Full control via your webhook | External service (Zenchef, etc.) |
| Setup | Dashboard + webhook URL | Auto-detected by crawlers |
| Use case | Custom actions, integrations | Standard booking/ordering services |
| Examples | Contact form, quote request, newsletter | Zenchef, Resy, TheFork |
Configure capabilities in your Business Dashboard.
Public vs Private Capabilities
Each capability can be configured as public or private, controlling who can execute the action.
Important: All capability executions require OAuth authentication. The public/private distinction controls who can execute the action once authenticated.
| Type | Who can execute | Use Case |
|---|---|---|
| Public | Any authenticated user | Customer-facing actions (booking, contact, catalog) |
| Private | Organization members only | Internal tools, admin actions, team-only features |
Public Capabilities
Public capabilities can be executed by any authenticated user. These are your customer-facing actions that anyone should be able to use.
Typical public capabilities:
book- Customers can make reservationssend_message- Customers can contact your teamsearch_catalog- Anyone can browse productsget_availability- Check available time slotsrequest_quote- Request pricing informationsubscribe- Subscribe to newsletter
Private Capabilities
Private capabilities are restricted to members of your organization. Use these for internal tools that should not be accessible to the public.
Examples of private capabilities:
view_bookings- Staff view of all reservationsupdate_inventory- Manage stock levelsexport_customers- Download customer datacancel_booking- Admin booking managementsend_notification- Internal team alerts
Organization membership: Users become organization members when invited via the Organization Settings. Members can then execute private capabilities using their personal OAuth tokens.
How Authentication Works
When executing any capability (public or private), the flow is:
- User asks AI agent to perform an action (e.g., "Book a table")
- AI agent calls
execute_actionvia MCP - If not authenticated, MCP client prompts user to sign in via Dock AI OAuth
- User authenticates with email (6-digit OTP, no password)
- For private capabilities: system checks organization membership
- Action executes with user's verified email in webhook payload
Configuring Visibility
Set the visibility of each capability in your Business Dashboard. Toggle the "Private (org members only)" switch to restrict access to your team.
Default behavior: All capabilities are public by default, allowing any authenticated user to execute them. Enable private mode only for internal/admin capabilities.
Standard Actions
Dock AI provides 6 standard action types with pre-configured schemas. Using standard slugs improves AI understanding and discoverability.
send_message - Contact
Allow customers to send messages to your team.
AI Description: "Use this action to send a message to [business]. The message will be forwarded to the team."
Default fields: name (required), email (required), subject, message (required)
book - Booking
Allow bookings for tables, appointments, or services.
AI Description: "Use this action to make a booking at [business]. Returns a confirmation of the booking request."
Default fields: date (required), time (required), guests (required), name (required), phone, notes
search_catalog - Catalog
Allow searching through your products or services.
AI Description: "Use this action to search the [business] catalog. Returns a list of matching products/services."
Default fields: query (required), category, limit
get_availability - Availability
Show available time slots.
AI Description: "Use this action to check availability at [business]. Returns available time slots."
Default fields: date, service
request_quote - Quote
Allow quote requests from customers.
AI Description: "Use this action to request a quote from [business]. The team will get back to you with a proposal."
Default fields: name (required), email (required), phone, description (required), budget
subscribe - Newsletter
Allow newsletter subscriptions for news and offers.
AI Description: "Use this action to subscribe to the [business] newsletter for news and offers."
Default fields: email (required), name
Custom Webhooks
Create custom capabilities with your own webhook endpoints. This gives you full control over the action execution.
Slug Naming Conventions
Custom slugs must follow these rules:
- Start with a lowercase letter:
a-z - Contain only lowercase letters, numbers, and underscores:
a-z0-9_ - Maximum 50 characters
- Pattern:
/^[a-z][a-z0-9_]*$/
Good: check_order_status, schedule_callback, get_menu
Bad: Check-Order, 2fa_verify, get menu
AI Description Best Practices
Write clear descriptions that help AI agents understand when to use this action:
- Start with "Use this action to..."
- Explain what the action does and what it returns
- Include any constraints (hours, limits, requirements)
- Keep it under 200 characters
Webhook URL Requirements
Security Requirements: Webhook URLs are validated to prevent SSRF attacks.
- HTTPS required - HTTP URLs are rejected
- No private IPs - 127.x.x.x, 10.x.x.x, 192.168.x.x, 172.16-31.x.x blocked
- No localhost - localhost and ::1 blocked
- Domain names only - Raw IP addresses rejected
- Blocked ports: 22 (SSH), 23 (Telnet), 25 (SMTP), 3306 (MySQL), 5432 (PostgreSQL), 6379 (Redis), 27017 (MongoDB)
Input Fields Configuration
Configure the data your webhook will receive using the visual form editor in your Business Dashboard. For each field, you can set:
- Field key - Technical name (lowercase, underscores only)
- Label - Display name shown to the AI
- Type - Text, Number, or Yes/No
- Format - Email, Date, Time, Phone (for validation)
- Required - Toggle on/off
Technical reference: The form generates a JSON schema that is sent with each webhook request. Here is an example of what the book action schema looks like:
{
"date": {
"type": "string",
"format": "date",
"required": true,
"label": "Date",
"placeholder": "YYYY-MM-DD"
},
"time": {
"type": "string",
"format": "time",
"required": true,
"label": "Time",
"placeholder": "HH:MM"
},
"guests": {
"type": "number",
"required": true,
"label": "Number of guests",
"min": 1,
"max": 20
},
"name": {
"type": "string",
"required": true,
"label": "Name",
"placeholder": "Name for the booking",
"maxLength": 100
},
"phone": {
"type": "string",
"format": "phone",
"required": false,
"label": "Phone",
"placeholder": "+1 555 123 4567"
},
"notes": {
"type": "string",
"required": false,
"label": "Notes",
"placeholder": "Allergies, special occasion...",
"maxLength": 500
}
}Field Types
| Type | Description | Validations |
|---|---|---|
| string | Text value | maxLength |
| number | Numeric value | min, max |
| boolean | True/false | - |
String Formats
| Format | Description | Example |
|---|---|---|
| Email address | user@example.com | |
| date | Date (YYYY-MM-DD) | 2025-02-15 |
| time | Time (HH:MM) | 20:00 |
| phone | Phone number | +33612345678 |
| url | URL | https://example.com |
Field Properties
| Property | Type | Description |
|---|---|---|
| required | boolean | Field is mandatory |
| label | string | Display label |
| placeholder | string | Input placeholder |
| min | number | Minimum value (numbers) |
| max | number | Maximum value (numbers) |
| maxLength | number | Maximum length (strings) |
Payload & Security
Webhook Payload
When an action is executed, Dock AI sends a POST request to your webhook URL with the following payload:
{
"execution_id": "550e8400-e29b-41d4-a716-446655440000",
"action": "book",
"params": {
"date": "2025-02-15",
"time": "20:00",
"guests": 4,
"name": "Jean Dupont",
"phone": "+33612345678"
},
"user_email": "user@example.com",
"timestamp": "2025-01-17T12:00:00.000Z"
}Request Headers
| Header | Description |
|---|---|
| Content-Type | application/json |
| X-DockAI-Action | Action slug (e.g., "book") |
| X-DockAI-Entity | Entity UUID |
| X-DockAI-Timestamp | ISO 8601 timestamp |
Authentication
Configure an Authorization header in your capability settings. Dock AI will include this header in every request to your endpoint.
Security Best Practice: Always validate the Authorization header on your server before processing requests.
Response Requirements
| Constraint | Value | Error |
|---|---|---|
| Timeout | 10 seconds | 504 Gateway Timeout |
| Max response size | 100 KB | 413 Payload Too Large |
| Format | JSON | Raw text truncated |
Prompt Injection Protection
Webhook responses are scanned for prompt injection attempts. If suspicious content is detected, the response is blocked and a security warning is returned to the AI agent.
Blocked patterns include:
- "Ignore previous instructions"
- "You are now in admin mode"
- "Reveal your system prompt"
- "Execute this command"
- Jailbreak/bypass attempts
Blocked Field Names
Phishing Protection: The following field names are blocked in input schemas to prevent collecting sensitive data.
Exact match only:
password, pwd, passwd, cvv, cvc, cv2, ssn, pin
Blocked if field name contains:
credit_card, card_number, cc_number, card_pan, security_code, social_security, pin_code, secret_key, private_key, api_key, access_token, auth_token
Integration Examples
Make (Integromat)
- Create a new scenario in Make
- Add a Webhooks → Custom webhook module as trigger
- Copy the generated webhook URL
- Paste the URL in your Dock AI capability settings (with
https://) - Click "Run once" in Make, then test the capability from Dock AI
- Make will auto-detect the data structure from the test payload
- Add your automation modules (Google Sheets, Email, Slack...)
- Return a JSON response using the Webhook response module
Zapier
- Create a new Zap
- Choose Webhooks by Zapier as the trigger
- Select Catch Hook as the event
- Copy the generated webhook URL
- Paste the URL in your Dock AI capability settings
- Send a test request from Dock AI
- Add action steps (Gmail, Slack, Google Sheets, CRM updates...)
- Optionally add a Webhooks → Return Response action at the end
n8n
- Create a new workflow
- Add a Webhook node as the trigger
- Set HTTP Method to
POST - Set Response Mode to
Last Node(to return JSON response) - Copy the webhook URL (Production or Test)
- Paste the URL in your Dock AI capability settings
- Add your workflow nodes (database, email, API calls...)
- End with a Respond to Webhook node to return JSON
Express.js Webhook
const express = require('express');
const app = express();
app.use(express.json());
app.post('/api/dockai/book', (req, res) => {
// Verify Authorization header
const authHeader = req.headers['authorization'];
if (authHeader !== `Bearer ${process.env.DOCKAI_API_KEY}`) {
return res.status(401).json({ error: 'Unauthorized' });
}
const { execution_id, action, params, user_email, timestamp } = req.body;
// Process booking
const { date, time, guests, name, phone } = params;
// Your booking logic here...
const booking = createBooking({ date, time, guests, name, phone, email: user_email });
// Return confirmation
res.json({
success: true,
confirmation: `Booking confirmed for ${guests} guests on ${date} at ${time}`,
reference: booking.id
});
});
app.listen(3000);FastAPI Webhook
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel
from typing import Dict, Any
import os
app = FastAPI()
class WebhookPayload(BaseModel):
execution_id: str
action: str
params: Dict[str, Any]
user_email: str
timestamp: str
@app.post("/api/dockai/book")
async def handle_booking(request: Request, payload: WebhookPayload):
# Verify Authorization header
auth_header = request.headers.get("authorization")
if auth_header != f"Bearer {os.environ['DOCKAI_API_KEY']}":
raise HTTPException(status_code=401, detail="Unauthorized")
# Extract booking params
date = payload.params.get("date")
time = payload.params.get("time")
guests = payload.params.get("guests")
name = payload.params.get("name")
# Your booking logic here...
booking = create_booking(date=date, time=time, guests=guests, name=name)
return {
"success": True,
"confirmation": f"Booking confirmed for {guests} guests on {date} at {time}",
"reference": booking.id
}Rate Limiting
Each capability has its own rate limit to prevent abuse. Limits are tracked per user (hashed user ID for privacy).
| Setting | Default | Range |
|---|---|---|
| Rate limit per user | 20 requests/hour | 1-1000/hour |
| Global IP limit | 30 requests/hour | Fixed |
Configure rate limits in your Business Dashboard under each capability's settings.
Troubleshooting
| Code | Error | Solution |
|---|---|---|
| 401 | Auth required | Verify Bearer token in Authorization header |
| 400 | Invalid params | Check params match the input_schema |
| 404 | Action not found | Verify slug and entity_id; ensure capability is enabled |
| 429 | Rate limit exceeded | Wait for the window to reset or increase the limit |
| 502 | Webhook error | Check webhook URL is reachable and returns valid JSON |
| 504 | Timeout | Optimize webhook to respond in <10 seconds |
| 413 | Response too large | Reduce response size to <100KB |
Webhook not receiving requests
- Verify the URL is HTTPS (HTTP is rejected)
- Check the URL doesn't point to a private IP
- Ensure your server accepts POST requests
- Check firewall rules allow incoming connections
Signature verification fails
- Ensure you're using the exact secret from the dashboard
- Sign the raw JSON string (not parsed object) with the same serialization
- Use HMAC-SHA256 algorithm
- Compare signature in lowercase hex format
Response blocked
- Check your response doesn't contain AI manipulation phrases
- Remove any "system prompt" or "ignore instructions" text
- Return clean JSON data without embedded instructions
Need help?
Contact us at support@dockai.co