Overview
Entro's Webhook integration lets your AI agents push content to any external platform via standard HTTP requests. Unlike platform-specific integrations (WordPress, Notion, etc.), webhooks give you full control over how and where content is delivered.
Common use cases:
- Publish blog posts to a custom CMS or static site generator
- Send notifications to internal tools (Slack alternatives, Discord, etc.)
- Push data to a headless e-commerce platform
- Trigger CI/CD pipelines or automation workflows
- Sync content to any REST API
How It Works
The flow is straightforward:
- You register a webhook endpoint in Entro's Settings → Integrations page.
- When your AI agent needs to publish content, it sends an HTTP request to your endpoint with a JSON payload.
- Your server receives the request, validates the authentication, and processes the content however you need.
┌─────────────┐ HTTP POST/PUT/PATCH ┌──────────────────┐
│ Entro Agent │ ───────────────────────► │ Your Server │
│ │ + Auth Header │ (webhook receiver)│
│ "Publish │ + JSON Body │ │
│ this post" │ │ Process content │
└─────────────┘ └──────────────────┘Setting Up in Entro
- Go to Settings → Integrations in your Entro dashboard.
- Find the Webhook card and click Add Webhook.
- Fill in the form:
- URL — Your server's endpoint (e.g.
https://yoursite.com/api/entro-webhook) - Label — A friendly name (e.g. “My Blog”)
- Method — POST (default), PUT, or PATCH
- Authentication — Choose Header, Query Parameter, or None
- Token / API Key — Your secret for authenticating requests
- URL — Your server's endpoint (e.g.
- Click Add. Entro will verify your endpoint is reachable before saving.
You can add multiple webhook endpoints — your agents can publish to different platforms simultaneously.
Building Your Receiver Endpoint
Your webhook receiver is a standard HTTP endpoint that accepts JSON. Here's what it needs to do:
- Accept the configured HTTP method (POST, PUT, or PATCH)
- Validate authentication (check the token/key)
- Parse the JSON body and process the content
- Return a response (2xx for success, 4xx/5xx for errors)
Request Format
Headers
Every request includes Content-Type: application/json. Depending on your authentication configuration:
// Header authentication (most common)
POST /api/entro-webhook HTTP/1.1
Host: yoursite.com
Content-Type: application/json
Authorization: Bearer your-secret-token
// Query parameter authentication
POST /api/entro-webhook?token=your-secret-token HTTP/1.1
Host: yoursite.com
Content-Type: application/json
// No authentication
POST /api/entro-webhook HTTP/1.1
Host: yoursite.com
Content-Type: application/jsonRequest Body
The JSON body structure depends on what your agent sends. Entro agents are flexible — you can instruct them to format the payload to match your API. A typical content-publishing payload looks like:
{
"title": "How to Build a REST API",
"content": "<h2>Introduction</h2><p>In this guide...</p>",
"status": "draft",
"excerpt": "A step-by-step guide to building REST APIs.",
"categories": ["tutorials", "backend"],
"tags": ["api", "rest", "nodejs"],
"author": "Entro Agent",
"metadata": {
"seo_title": "How to Build a REST API | My Blog",
"seo_description": "Learn how to build a REST API...",
"featured_image": "https://example.com/images/api-guide.jpg"
}
}Tip: You can customize what your agent sends by describing the expected payload format in the agent's system prompt. For example: “When publishing to the webhook, always include title, content, status, and categories fields.”
Authentication
Entro supports three authentication methods:
1. Header Authentication (Recommended)
The token is sent in an HTTP header. You choose the header name when configuring the webhook (defaults to Authorization).
// Default: Authorization header
Authorization: Bearer your-secret-token
// Custom header (e.g. X-API-Key)
X-API-Key: your-secret-token2. Query Parameter Authentication
The token is appended to the URL as a query parameter named token.
POST /api/entro-webhook?token=your-secret-token3. No Authentication
No token is sent. Only use this for internal endpoints on private networks. Not recommended for production.
Expected Response
Your endpoint should return a JSON response. The agent reads the response to confirm success or handle errors:
// Success (200 OK)
{
"success": true,
"id": "post-123",
"url": "https://yoursite.com/blog/how-to-build-a-rest-api"
}
// Error (400 Bad Request)
{
"error": "Missing required field: title"
}
// Error (401 Unauthorized)
{
"error": "Invalid authentication token"
}Code Examples
Node.js (Express)
const express = require("express");
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
app.post("/api/entro-webhook", (req, res) => {
// 1. Validate authentication
const authHeader = req.headers["authorization"];
if (!authHeader || authHeader !== `Bearer ${WEBHOOK_SECRET}`) {
return res.status(401).json({ error: "Unauthorized" });
}
// 2. Process the content
const { title, content, status, categories } = req.body;
if (!title || !content) {
return res.status(400).json({ error: "title and content are required" });
}
// 3. Save to your database, CMS, or file system
console.log("Received:", { title, status, categories });
// await db.posts.create({ title, content, status, categories });
// 4. Return success
res.json({
success: true,
id: "post-" + Date.now(),
message: "Content received successfully",
});
});
app.listen(3000, () => console.log("Webhook receiver running on :3000"));Python (Flask)
from flask import Flask, request, jsonify
import os
app = Flask(__name__)
WEBHOOK_SECRET = os.environ.get("WEBHOOK_SECRET")
@app.route("/api/entro-webhook", methods=["POST"])
def entro_webhook():
# 1. Validate authentication
auth = request.headers.get("Authorization", "")
if auth != f"Bearer {WEBHOOK_SECRET}":
return jsonify({"error": "Unauthorized"}), 401
# 2. Process the content
data = request.get_json()
title = data.get("title")
content = data.get("content")
if not title or not content:
return jsonify({"error": "title and content are required"}), 400
# 3. Save to your database
print(f"Received: {title}")
# db.posts.create(title=title, content=content, ...)
# 4. Return success
return jsonify({
"success": True,
"message": "Content received successfully",
})
if __name__ == "__main__":
app.run(port=3000)PHP
<?php
// api/entro-webhook.php
$WEBHOOK_SECRET = getenv("WEBHOOK_SECRET");
// 1. Validate authentication
$headers = getallheaders();
$auth = $headers["Authorization"] ?? "";
if ($auth !== "Bearer " . $WEBHOOK_SECRET) {
http_response_code(401);
echo json_encode(["error" => "Unauthorized"]);
exit;
}
// 2. Parse the JSON body
$body = json_decode(file_get_contents("php://input"), true);
$title = $body["title"] ?? null;
$content = $body["content"] ?? null;
if (!$title || !$content) {
http_response_code(400);
echo json_encode(["error" => "title and content are required"]);
exit;
}
// 3. Save to your database
// $pdo->prepare("INSERT INTO posts ...")->execute([...]);
// 4. Return success
http_response_code(200);
echo json_encode([
"success" => true,
"message" => "Content received successfully",
]);Next.js (App Router)
// app/api/entro-webhook/route.ts
import { NextRequest, NextResponse } from "next/server";
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET!;
export async function POST(req: NextRequest) {
// 1. Validate authentication
const auth = req.headers.get("authorization");
if (auth !== `Bearer ${WEBHOOK_SECRET}`) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
// 2. Parse the body
const { title, content, status } = await req.json();
if (!title || !content) {
return NextResponse.json(
{ error: "title and content are required" },
{ status: 400 }
);
}
// 3. Save to your database
// await prisma.post.create({ data: { title, content, status } });
// 4. Return success
return NextResponse.json({
success: true,
message: "Content received successfully",
});
}Testing Your Webhook
Using webhook.site
Before building your own endpoint, you can test the integration using webhook.site:
- Go to webhook.site and copy your unique URL
- Add it as a webhook endpoint in Entro (Settings → Integrations)
- Ask your agent to publish something — you'll see the request appear in real-time
Using curl
Test your own endpoint locally:
curl -X POST http://localhost:3000/api/entro-webhook \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-secret-token" \
-d '{
"title": "Test Post",
"content": "<p>Hello from Entro!</p>",
"status": "draft"
}'Security Best Practices
- Always use HTTPS in production — tokens are sent in headers/URLs and must be encrypted in transit
- Use Header authentication over query parameters — query strings can appear in server logs
- Generate strong tokens — use at least 32 characters with mixed case, numbers, and symbols
- Validate the request body — never trust incoming data; always sanitize HTML content before storing
- Rate-limit your endpoint — protect against abuse with reasonable rate limits
- Return minimal error details — don't expose internal error messages or stack traces
Troubleshooting
“Could not reach” error when adding the webhook
Entro verifies your endpoint is reachable when you add it. Make sure:
- Your server is running and publicly accessible
- The URL is correct (check for typos)
- Your firewall allows inbound HTTP requests
- If using a local development server, expose it with a tunneling service like ngrok
401 / 403 errors
- Double-check that the token in Entro matches the one your server expects
- Verify you're checking the correct header name (e.g.
AuthorizationvsX-API-Key) - Make sure your auth check includes the
Bearerprefix if your token format requires it
Empty or malformed body
- Ensure your server parses JSON bodies (e.g.
express.json()in Express,request.get_json()in Flask) - Check that
Content-Type: application/jsonis being sent (Entro always sends this)
Agent doesn't send the right fields
Customize the payload by adding instructions to your agent's system prompt:
When publishing content via webhook, always send a JSON body with:
- "title": the post title (string)
- "content": the full HTML content (string)
- "status": "draft" or "publish" (string)
- "categories": array of category slugs
- "featured_image": URL to the featured image (if available)Need Help?
If you run into issues with the Webhook integration, reach out through our Telegram community or email us at support@entro.work.