Webhooks
HTTP webhooks let external systems trigger agents via HTTP requests. They support JSON, form data, and file uploads.
On this page
Setup Instructions
Create the connector
Open the agent, click Add inbound connector in the Connector Flow, then Create New Connector and select HTTP Webhook.
Select Inbound (Fire & Forget) and copy credentials
Choose the mode and click Create. The detail drawer opens automatically with the Webhook URL and Secret in the Configuration section. To view them later, hover over the connector in the Connector Flow and click the Eye icon.
Send requests
Send requests from the application to the URL, passing the secret in the
X-Connic-Secretheader when connector authentication is enabled.
How Inbound Works
When an inbound webhook receives a request, it queues the agent run and returns a response with the run IDs. The agent processes in the background. Best for background processing, high-volume ingestion, and event-driven architectures.
Response Format
{
"status": "ok",
"dispatched_to": 2,
"run_ids": [
"550e8400-e29b-41d4-a716-446655440000",
"550e8400-e29b-41d4-a716-446655440001"
]
}Sending Requests
Webhooks accept both GET and POST requests with various content types.
JSON Requests
The most common way to trigger webhooks. Send a POST request with a JSON body (application/json). JSON fields are passed to the agent as input. Inline files use the attachment limits below.
curl -X POST <webhook-url> \
-H "Content-Type: application/json" \
-H "X-Connic-Secret: <your-secret-key>" \
-d '{
"prompt": "Analyze this data",
"data": {"key": "value"}
}'Form Data Requests
Useful for simple integrations or when the source system sends form data (application/x-www-form-urlencoded). Each form field becomes a key-value pair in the payload.
curl -X POST <webhook-url> \
-H "X-Connic-Secret: <your-secret-key>" \
-F "message=Process this invoice" \
-F "customer_id=12345"GET Requests
For simple triggers, use GET requests with query parameters. All query parameters (except secret) are passed to the agent.
curl "<webhook-url>?secret=<your-secret-key>&prompt=hello"Get the Webhook URL & Secret
The webhook URL includes the connector ID, and the X-Connic-Secret is generated when the connector is created. Authentication is enabled by default. Disable Require Authentication only for an intentionally unauthenticated endpoint.
Open the agent detail page in the Agents section
Add a webhook connector via the + button on the connector flow, or select an existing one
Click the eye icon on the connector to open its details
Copy the Webhook URL and Secret from the connector details
File Uploads
Send files to agents using multipart/form-data. Files are passed directly to the LLM for analysis.
Files are extracted and sent to the model as inline data:
curl -X POST <webhook-url> \
-H "X-Connic-Secret: <your-secret-key>" \
-F "instructions=What is the total of this invoice?" \
-F "file=@/path/to/invoice.pdf"Upload multiple files in a single request:
curl -X POST <webhook-url> \
-H "X-Connic-Secret: <your-secret-key>" \
-F "message=Compare these two documents" \
-F "file1=@document1.pdf" \
-F "file2=@document2.pdf"Multipart requests land in context["payload"] as a normalised dict with text parts as top-level keys and uploads under files (each file's bytes are base64-encoded). The LLM-facing content is reconstructed automatically: each file becomes a binary part, and the leading text part is the payload with only files removed.
# context["payload"] inside middleware before()
{
"customer_id": "12345", # multipart text fields sit at the top level
"tag": ["a", "b"], # repeated keys are grouped into a list
"message": "Process this invoice",
"files": [
{
"name": "invoice.pdf", # original filename
"field_name": "file", # form field name
"mime_type": "application/pdf",
"data": "<base64-bytes>", # always base64-encoded ASCII
"size": 12345 # bytes
}
]
}
# Omitted files are described in "file_issues". Form fields remain available
# even when no file is accepted.An input accepts up to 10 files, at most 10 MiB per file and 10 MiB combined. At the first count or size overflow, Connic keeps earlier complete files and stops accepting later files. Form fields remain available even if no file is accepted. Unsupported MIME types are omitted with a reason in file_issues.
The response reports accepted, omitted, and issues when attachments are present. Files are optional by default. Enable Files required on the agent link, or set files_required: true in its configuration, to fail the run before execution when a file is missing or omitted. Later input review can also omit optional file content that exceeds its review budget.
Images
JPEG, PNG, GIF, WebP, HEIC/HEIF
Documents
PDF, Word, RTF, OpenDocument, EPUB, Plain text, HTML, Markdown
Data & Office
CSV, TSV, JSON, XML, Excel, PowerPoint
request_too_large before processing; the sender must retry with a smaller body.Authentication
Secure webhooks with secret-based authentication. Inbound and sync webhooks require this secret by default. Turn off Require Authentication only when callers do not need to authenticate.
Providing the Secret
Each webhook has a unique secret key generated when created. When Require Authentication is enabled, provide it in three ways:
- X-Connic-Secret Header (Recommended) - Most secure, secret is in headers
- Authorization: Bearer Header - Standard OAuth-style bearer token
- Query Parameter (?secret=...) - Less secure, visible in logs
# Using X-Connic-Secret header (recommended)
curl -X POST <webhook-url> \
-H "X-Connic-Secret: <your-secret-key>" \
-d '{"message": "hello"}'
# Using Authorization: Bearer header
curl -X POST <webhook-url> \
-H "Authorization: Bearer <your-secret-key>" \
-d '{"message": "hello"}'
# Using query parameter (less secure)
curl -X POST "<webhook-url>?secret=<your-secret-key>" \
-d '{"message": "hello"}'Error Responses
401Invalid secret key
The provided secret doesn't match. Check the authentication settings.
404Webhook not found
The webhook URL doesn't exist. Check the URL is correct.
400Outbound-only webhook
This webhook is configured for outbound only and cannot be triggered.
Setup Instructions
Set up an endpoint
Create an endpoint on the server that can receive POST requests.
Create the connector
Open the agent, click Add outbound connector, then Create New Connector and select HTTP Webhook.
Configure and create
Choose Outbound mode, enter the destination URL where Connic should POST results, optionally select a Bridge for private network access, and click Create. Results from linked agents will be POSTed to the configured URL with signature headers.
How Outbound Works
Automatic outbound webhooks send agent results to an external URL when runs complete. Agent-tool and middleware outbound webhooks send when called during a run. The connector uses a configured destination URL, and Connic POSTs the results there. For private endpoints, route outbound requests through a Connic Bridge. Best for sending results to external APIs, integrating with third-party services, and building event pipelines.
Automatic Payload
Automatic outbound connectors POST the completed-run envelope. Existing links remain automatic for all runs unless their mode or source filter changes.
{
"run_id": "550e8400-e29b-41d4-a716-446655440000",
"agent_name": "invoice-processor",
"status": "completed",
"output": "The invoice total is $1,234.56",
"error": null,
"started_at": "2024-01-15T10:30:00Z",
"ended_at": "2024-01-15T10:30:05Z",
"token_usage": {
"input_tokens": 150,
"output_tokens": 50,
"thinking_tokens": 0,
"cached_input_tokens": 0,
"total_tokens": 200
}
}Agent-tool and Middleware Outbound Connectors
Agent-tool outbound connectors expose an editable tool name, which defaults to send_to_<connector_name>. Call middleware outbound connectors by their configured name with send_connector(action_name, payload). Both use the same connector-owned payload schema: pass the JSON body under payload.
{
"payload": {
"invoice_id": "inv_123",
"status": "approved"
}
}Connic POSTs the nested value and applies the connector's URL, configured headers, HMAC signature, retries, and Bridge routing. Those settings are not exposed to the model.
Signature Verification
Every outbound webhook request includes an HMAC-SHA256 signature. Verify it to ensure requests are authentic.
Request Headers
X-Connic-Signature- Hex-encoded HMAC-SHA256 signatureX-Connic-Timestamp- Unix timestamp (seconds) when the request was signed
How to Verify
Get the signing secret from the connector settings
Extract the timestamp and signature from headers
Concatenate timestamp + "." + raw request body
Compute HMAC-SHA256 of the concatenated string using the secret
Compare the computed signature with the received one
Optionally check timestamp is within 5 minutes to prevent replay attacks
Python Example
import hmac
import hashlib
import time
def verify_webhook(payload: bytes, signature: str, timestamp: str, secret: str) -> bool:
"""Verify a Connic webhook signature."""
# Check timestamp is not too old (5 minute window)
if abs(time.time() - int(timestamp)) > 300:
return False
# Build the signed payload
signed_payload = f"{timestamp}.".encode() + payload
# Compute expected signature
expected = hmac.new(
secret.encode(),
signed_payload,
hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
# Usage in Flask
@app.route("/webhook", methods=["POST"])
def handle_webhook():
signature = request.headers.get("X-Connic-Signature", "")
timestamp = request.headers.get("X-Connic-Timestamp", "")
if not verify_webhook(request.data, signature, timestamp, SIGNING_SECRET):
return "Invalid signature", 401
# Process the webhook...
return "OK", 200Node.js Example
import crypto from 'crypto';
function verifyWebhook(payload, signature, timestamp, secret) {
// Check timestamp is not too old (5 minute window)
const now = Math.floor(Date.now() / 1000);
if (Math.abs(now - parseInt(timestamp)) > 300) {
return false;
}
// Build the signed payload
const signedPayload = `${timestamp}.${payload}`;
// Compute expected signature
const expected = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(signature)
);
}
// Usage in Express
app.post('/webhook', express.raw({ type: 'application/json' }), (req, res) => {
const signature = req.headers['x-connic-signature'];
const timestamp = req.headers['x-connic-timestamp'];
if (!verifyWebhook(req.body.toString(), signature, timestamp, SIGNING_SECRET)) {
return res.status(401).send('Invalid signature');
}
// Process the webhook...
res.send('OK');
});- Always verify signatures in production
- Use constant-time comparison to prevent timing attacks
- Reject requests with timestamps older than 5 minutes
- Store the signing secret securely (environment variables)
How Sync Works
Sync webhooks wait for the agent to complete and return the result in the same HTTP response. A traditional request-response pattern. Best for REST API integrations, interactive applications, and short-running tasks.
Setup Instructions
Create the connector
Open the agent, click Add inbound connector in the Connector Flow, then Create New Connector and select HTTP Webhook.
Select Sync (Request-Response) and copy credentials
Choose the mode and click Create. The detail drawer opens automatically with the Webhook URL and Secret in the Configuration section. To view them later, hover over the connector in the Connector Flow and click the Eye icon.
Send requests
POST JSON to the webhook URL. The response blocks until the agent finishes and returns the result inline.
Response Format
{
"status": "ok",
"result": {
"run_id": "550e8400-e29b-41d4-a716-446655440000",
"agent_name": "invoice-processor",
"status": "completed",
"output": "The invoice total is $1,234.56",
"error": null
}
}A failed agent run returns status: "failed" with its error and is recorded as a failed connector run.
Client Examples
import requests
url = "<webhook-url>"
secret = "<your-secret-key>"
payload = {"query": "What is the status of order 123?"}
resp = requests.post(
url,
json=payload,
headers={"X-Connic-Secret": secret},
timeout=310,
)
resp.raise_for_status()
print(resp.json()["result"]["output"])import fetch from "node-fetch";
const url = "<webhook-url>";
const secret = "<your-secret-key>";
const resp = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Connic-Secret": secret,
},
body: JSON.stringify({ query: "Summarize the latest ticket" }),
});
if (!resp.ok) throw new Error(await resp.text());
const data = await resp.json();
console.log(data.result.output);Sending Requests
Webhooks accept both GET and POST requests with various content types.
JSON Requests
The most common way to trigger webhooks. Send a POST request with a JSON body (application/json). JSON fields are passed to the agent as input. Inline files use the attachment limits below.
curl -X POST <webhook-url> \
-H "Content-Type: application/json" \
-H "X-Connic-Secret: <your-secret-key>" \
-d '{
"prompt": "Analyze this data",
"data": {"key": "value"}
}'Form Data Requests
Useful for simple integrations or when the source system sends form data (application/x-www-form-urlencoded). Each form field becomes a key-value pair in the payload.
curl -X POST <webhook-url> \
-H "X-Connic-Secret: <your-secret-key>" \
-F "message=Process this invoice" \
-F "customer_id=12345"GET Requests
For simple triggers, use GET requests with query parameters. All query parameters (except secret) are passed to the agent.
curl "<webhook-url>?secret=<your-secret-key>&prompt=hello"Get the Webhook URL & Secret
The webhook URL includes the connector ID, and the X-Connic-Secret is generated when the connector is created. Authentication is enabled by default. Disable Require Authentication only for an intentionally unauthenticated endpoint.
Open the agent detail page in the Agents section
Add a webhook connector via the + button on the connector flow, or select an existing one
Click the eye icon on the connector to open its details
Copy the Webhook URL and Secret from the connector details
File Uploads
Send files to agents using multipart/form-data. Files are passed directly to the LLM for analysis.
Files are extracted and sent to the model as inline data:
curl -X POST <webhook-url> \
-H "X-Connic-Secret: <your-secret-key>" \
-F "instructions=What is the total of this invoice?" \
-F "file=@/path/to/invoice.pdf"Upload multiple files in a single request:
curl -X POST <webhook-url> \
-H "X-Connic-Secret: <your-secret-key>" \
-F "message=Compare these two documents" \
-F "file1=@document1.pdf" \
-F "file2=@document2.pdf"Multipart requests land in context["payload"] as a normalised dict with text parts as top-level keys and uploads under files (each file's bytes are base64-encoded). The LLM-facing content is reconstructed automatically: each file becomes a binary part, and the leading text part is the payload with only files removed.
# context["payload"] inside middleware before()
{
"customer_id": "12345", # multipart text fields sit at the top level
"tag": ["a", "b"], # repeated keys are grouped into a list
"message": "Process this invoice",
"files": [
{
"name": "invoice.pdf", # original filename
"field_name": "file", # form field name
"mime_type": "application/pdf",
"data": "<base64-bytes>", # always base64-encoded ASCII
"size": 12345 # bytes
}
]
}
# Omitted files are described in "file_issues". Form fields remain available
# even when no file is accepted.An input accepts up to 10 files, at most 10 MiB per file and 10 MiB combined. At the first count or size overflow, Connic keeps earlier complete files and stops accepting later files. Form fields remain available even if no file is accepted. Unsupported MIME types are omitted with a reason in file_issues.
The response reports accepted, omitted, and issues when attachments are present. Files are optional by default. Enable Files required on the agent link, or set files_required: true in its configuration, to fail the run before execution when a file is missing or omitted. Later input review can also omit optional file content that exceeds its review budget.
Images
JPEG, PNG, GIF, WebP, HEIC/HEIF
Documents
PDF, Word, RTF, OpenDocument, EPUB, Plain text, HTML, Markdown
Data & Office
CSV, TSV, JSON, XML, Excel, PowerPoint
request_too_large before processing; the sender must retry with a smaller body.Authentication
Secure webhooks with secret-based authentication. Inbound and sync webhooks require this secret by default. Turn off Require Authentication only when callers do not need to authenticate.
Providing the Secret
Each webhook has a unique secret key generated when created. When Require Authentication is enabled, provide it in three ways:
- X-Connic-Secret Header (Recommended) - Most secure, secret is in headers
- Authorization: Bearer Header - Standard OAuth-style bearer token
- Query Parameter (?secret=...) - Less secure, visible in logs
# Using X-Connic-Secret header (recommended)
curl -X POST <webhook-url> \
-H "X-Connic-Secret: <your-secret-key>" \
-d '{"message": "hello"}'
# Using Authorization: Bearer header
curl -X POST <webhook-url> \
-H "Authorization: Bearer <your-secret-key>" \
-d '{"message": "hello"}'
# Using query parameter (less secure)
curl -X POST "<webhook-url>?secret=<your-secret-key>" \
-d '{"message": "hello"}'Error Responses
401Invalid secret key
The provided secret doesn't match. Check the authentication settings.
404Webhook not found
The webhook URL doesn't exist. Check the URL is correct.
400Outbound-only webhook
This webhook is configured for outbound only and cannot be triggered.