Webhooks
HTTP webhooks allow external systems to trigger your agents via HTTP requests. They support JSON, form data, and file uploads.
Inbound Mode
Fire-and-forget triggers for asynchronous agent runs. The webhook returns immediately with run IDs while agents process in the background.
How Inbound Works
When an inbound webhook receives a request, it immediately 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). The entire JSON payload is passed to your agent as input.
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 your 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, you can 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 Your Webhook URL & Secret
The webhook URL includes your webhook_id, and theX-Connic-Secret is generated when you create the connector.
- Open your project → Connectors
- Select your webhook connector (or create one from the marketplace)
- Copy the Webhook URL and Secret from the connector details
- Link one or more agents to the connector
File Uploads
Send files to your agents using multipart/form-data. Files are passed directly to the LLM for analysis.
Files are automatically 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"You can 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"Supported File Types
Images
JPEG, PNG, GIF, WebP, HEIC/HEIF
Documents
PDF, Plain text, CSV, HTML, Markdown
File size limit: Maximum 10 MB per file.
Authentication
Secure your webhooks with secret-based authentication.
Providing the Secret
Each webhook has a unique secret key generated when created. You can 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 your authentication.
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.
Outbound Mode
Deliver agent results to external destinations. When agents complete, results are POSTed to your configured URL.
How Outbound Works
Outbound webhooks send agent results to an external URL when runs complete. You configure a destination URL, and Connic POSTs the results there. Best for sending results to external APIs, integrating with third-party services, and building event pipelines.
Note
Outbound-only webhooks cannot be triggered directly. They only send results when agents linked to them complete their runs.
Outbound Payload
What gets POSTed to your configured URL:
{
"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": {
"prompt_tokens": 150,
"candidates_tokens": 50,
"total_tokens": 200
}
}Signature Verification
Every outbound webhook request includes HMAC-SHA256 signatures for security. Verify these signatures 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 your connector settings
- Extract the timestamp and signature from headers
- Concatenate timestamp + "." + raw request body
- Compute HMAC-SHA256 of the concatenated string using your 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');
});Security Best Practices
- Always verify signatures in production
- Use constant-time comparison to prevent timing attacks
- Reject requests with timestamps older than 5 minutes
- Store your signing secret securely (environment variables)
Sync Mode
Request-response pattern with immediate results. The webhook waits for agent completion and returns the result in the same response.
How Sync Works
Sync webhooks wait for the agent to complete and return the result in the same HTTP response. This provides a traditional request-response pattern. Best for REST API integrations, interactive applications, and short-running tasks.
Timeout
Default timeout is 5 minutes. For longer tasks, use Inbound mode and poll for results.
Create a Sync Endpoint
- Create a webhook connector in Sync mode
- Link the agent you want to expose as an HTTP endpoint
- Copy the webhook URL and secret from the connector details
- Send JSON to the webhook URL; the response contains the agent output
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
}
}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=60,
)
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). The entire JSON payload is passed to your agent as input.
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 your 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, you can 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 Your Webhook URL & Secret
The webhook URL includes your webhook_id, and theX-Connic-Secret is generated when you create the connector.
- Open your project → Connectors
- Select your webhook connector (or create one from the marketplace)
- Copy the Webhook URL and Secret from the connector details
- Link one or more agents to the connector
File Uploads
Send files to your agents using multipart/form-data. Files are passed directly to the LLM for analysis.
Files are automatically 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"You can 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"Supported File Types
Images
JPEG, PNG, GIF, WebP, HEIC/HEIF
Documents
PDF, Plain text, CSV, HTML, Markdown
File size limit: Maximum 10 MB per file.
Authentication
Secure your webhooks with secret-based authentication.
Providing the Secret
Each webhook has a unique secret key generated when created. You can 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 your authentication.
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.