← 返回首页

🔗 Webhook 发布集成文档

指导你的服务器如何接收 GeoSight 的内容发布请求

工作原理

  1. 你在 GeoSight 设置页配置 Webhook URL(你的服务器端点)
  2. 用户在内容详情页点击「Webhook 发布」
  3. GeoSight 将内容以 JSON 格式 POST 到你的 URL
  4. 你的服务器接收内容,发布到自己的网站/CMS
  5. 你的服务器返回发布结果(含发布后的 URL)
  6. GeoSight 自动记录发布 URL,后续可追踪引用归因和收录状态

请求规范

GeoSight 发送到你服务器的 HTTP 请求

HTTP 方法

POST

Content-Type

application/json

请求头

Header说明
Content-Typeapplication/json
X-GeoSight-SignatureHMAC-SHA256 签名(格式:sha256=xxxx)
X-GeoSight-Event事件类型:content.publish 或 webhook.test
X-GeoSight-Delivery投递唯一 ID(UUID),用于幂等检查
X-GeoSight-TimestampUnix 时间戳(秒),用于签名和重放防护

请求体(Payload)

JSON 格式的内容数据

Payload 结构
JSON
{
  "event": "content.publish",
  "timestamp": "2026-08-29T22:00:00+08:00",
  "brand": {
    "name": "你的品牌名",
    "industry": "行业名称"
  },
  "content": {
    "title": "内容标题",
    "body_md": "# Markdown 格式内容\n\n## 小标题\n\n正文...",
    "body_html": "<h1>HTML 格式内容</h1><h2>小标题</h2><p>正文...</p>",
    "body_plain": "纯文本格式内容(无 Markdown/HTML 标记)",
    "json_ld": {
      "@context": "https://schema.org",
      "@graph": [
        { "@type": "Article", "headline": "标题", ... },
        { "@type": "FAQPage", "mainEntity": [...] }
      ]
    },
    "prompt_text": "触发此内容的用户提示词",
    "journey_stage": "research",
    "strategy_mode": "conservative",
    "strategy_score": 78
  },
  "seo": {
    "suggested_slug": "建议的 URL slug",
    "meta_title": "建议的 SEO 标题",
    "meta_description": "建议的 Meta 描述(≤160字)"
  },
  "source": {
    "gap_id": "GeoSight 内容差距 ID",
    "platform": "geosight"
  }
}

字段说明:

  • body_md — Markdown 原文,适合存储和后续编辑
  • body_html — 简易 HTML 转换,适合直接发布到 CMS
  • body_plain — 纯文本,适合搜索索引
  • json_ld — 结构化数据,建议嵌入页面 <head> 的 <script type="application/ld+json">
  • journey_stage — 用户旅程阶段:discovery(发现)/ research(调研)/ decision(决策)
  • strategy_score — GEO 策略得分(0-100),基于论文 S1-S6 元素量化

签名验证(必须)

验证请求确实来自 GeoSight,防止伪造

⚠ 安全要求

你的服务器必须验证签名。未经验证的请求可能被恶意第三方伪造。

签名算法:

  1. 拼接字符串:timestamp + "." + request_body
  2. 使用你的 签名密钥(在 GeoSight 设置页配置)做 HMAC-SHA256
  3. 与请求头 X-GeoSight-Signature 对比
签名验证逻辑(伪代码)
pseudo
received_signature = request.headers["X-GeoSight-Signature"]
timestamp = request.headers["X-GeoSight-Timestamp"]
body = request.raw_body  // 原始 JSON 字符串

expected = "sha256=" + HMAC-SHA256(secret, timestamp + "." + body)

if received_signature != expected:
    return 401 "签名无效"

// 可选:检查 timestamp 在 5 分钟内,防止重放
if abs(now() - int(timestamp)) > 300:
    return 401 "请求已过期"

响应规范

你的服务器需要返回的 JSON 格式

成功(含发布 URL)
JSON
{
  "ok": true,
  "url": "https://your-site.com/blog/your-article-slug",
  "message": "发布成功"
}
成功(无 URL,异步发布)
JSON
{
  "ok": true,
  "url": null,
  "message": "已接收,稍后发布"
}
失败
JSON
{
  "ok": false,
  "error": "分类不存在"
}

• 返回 ok: true 且有 url 时,GeoSight 会自动记录发布 URL 并可用于收录推送和引用归因

• 返回 ok: true 但无 url 时,GeoSight 标记为已接收但不记录 URL

• 返回 ok: false 或 HTTP 非 2xx 时,GeoSight 显示错误信息

幂等处理(建议)

GeoSight 每次投递都会生成唯一的 X-GeoSight-Delivery(UUID)。建议你的服务器记录已处理的 Delivery ID:

  • 收到请求时,先检查 Delivery ID 是否已处理过
  • 如果已处理,直接返回上次的结果(不重复发布)
  • 防止网络重试导致重复发布

示例代码

Node.js / Express
JavaScript
const express = require('express');
const crypto = require('crypto');
const app = express();

const SECRET = '你在GeoSight设置页看到的签名密钥';
const processedDeliveries = new Set(); // 生产环境用 Redis/DB

app.post('/api/geosight-webhook', express.raw({ type: '*/*' }), (req, res) => {
  // 1. 验签
  const sig = req.headers['x-geosight-signature'];
  const timestamp = req.headers['x-geosight-timestamp'];
  const body = req.body.toString();
  const expected = 'sha256=' + crypto.createHmac('sha256', SECRET)
    .update(timestamp + '.' + body).digest('hex');
  
  if (sig !== expected) {
    return res.status(401).json({ ok: false, error: '签名无效' });
  }

  // 2. 幂等检查
  const deliveryId = req.headers['x-geosight-delivery'];
  if (processedDeliveries.has(deliveryId)) {
    return res.json({ ok: true, url: null, message: '已处理' });
  }

  // 3. 解析内容
  const data = JSON.parse(body);
  const { content, seo, brand } = data;

  // 4. 发布到你的 CMS/数据库
  const slug = seo.suggested_slug;
  const url = `https://your-site.com/blog/${slug}`;
  
  // 示例:写入数据库
  // await db.posts.create({
  //   title: content.title,
  //   body: content.body_html,
  //   slug: slug,
  //   jsonLd: content.json_ld,
  //   metaTitle: seo.meta_title,
  //   metaDescription: seo.meta_description,
  // });

  console.log(`[GeoSight] 收到内容: ${content.title}`);

  // 5. 记录并返回
  processedDeliveries.add(deliveryId);
  res.json({ ok: true, url, message: '发布成功' });
});

app.listen(3000);
Python / FastAPI
Python
import hmac
import hashlib
from fastapi import FastAPI, Request, HTTPException
from pydantic import BaseModel

app = FastAPI()
SECRET = "你在GeoSight设置页看到的签名密钥"
processed = set()

@app.post("/api/geosight-webhook")
async def geosight_webhook(request: Request):
    # 1. 验签
    body = await request.body()
    sig = request.headers.get("x-geosight-signature", "")
    timestamp = request.headers.get("x-geosight-timestamp", "")
    
    expected = "sha256=" + hmac.new(
        SECRET.encode(), 
        f"{timestamp}.{body.decode()}".encode(), 
        hashlib.sha256
    ).hexdigest()
    
    if not hmac.compare_digest(sig, expected):
        raise HTTPException(401, "签名无效")

    # 2. 幂等检查
    delivery_id = request.headers.get("x-geosight-delivery", "")
    if delivery_id in processed:
        return {"ok": True, "url": None, "message": "已处理"}

    # 3. 解析内容
    import json
    data = json.loads(body)
    content = data["content"]
    seo = data["seo"]
    
    # 4. 发布到你的 CMS
    slug = seo["suggested_slug"]
    url = f"https://your-site.com/blog/{slug}"
    
    # await db.posts.create(title=content["title"], body=content["body_html"], ...)

    # 5. 记录并返回
    processed.add(delivery_id)
    return {"ok": True, "url": url, "message": "发布成功"}

测试方法

  1. 在 GeoSight 设置页填写你的 Webhook URL 和签名密钥,点击「保存配置」
  2. 点击「测试连接」—— GeoSight 会发送一个 webhook.test 事件到你的服务器
  3. 你的服务器正常响应即可(验签通过 + 返回 JSON)
  4. 进入任意内容详情页,点击「🔗 Webhook 发布」进行实际内容投递测试

调试提示:

测试连接时,X-GeoSight-Event 为 webhook.test,Payload 只有 event 和 timestamp 字段。你的代码应根据 event 字段区分测试事件和正式发布事件。

常见问题

Q: 我没有服务器怎么办?

A: 可以使用 Zapier / Make / n8n 等自动化平台的 Webhook 触发器接收数据,再转发到 WordPress / Notion / 其他 CMS。

Q: 支持批量发布吗?

A: 当前每次点击「Webhook 发布」发送一条内容。批量发布可多次点击,每次独立投递。

Q: 发布后内容更新了怎么办?

A: 再次点击「Webhook 发布」会重新投递最新版本。你的服务器可通过 source.gap_id 判断是新增还是更新。

Q: 签名密钥泄露了怎么办?

A: 在设置页重新保存 Webhook 配置(留空密钥字段会自动生成新密钥),同时更新你服务器的密钥。