OROVA.VN — BIZ AI AGENT

/ คู่มือสำหรับนักพัฒนา

รับโพสต์จาก Orova Social ผ่าน Webhook

วิธีสร้าง endpoint สำหรับรับโพสต์ที่ Orova Social ส่งมา และตรวจลายเซ็นก่อนนำไปใช้

Orova Social เผยแพร่ตรงไปยังแพลตฟอร์มที่เชื่อมไว้แล้ว หากต้องการให้โพสต์ไปถึงที่อื่น — ช่องทางภายในองค์กร แอปของคุณเอง หรือแพลตฟอร์มที่ Orova ยังไม่รองรับ — ให้ใช้ช่องทาง API: Orova จะส่งโพสต์ไปยังที่อยู่ HTTP ของคุณ พร้อมลงลายเซ็นด้วยคีย์ลับ แล้วที่เหลือเป็นหน้าที่ของคุณ หน้านี้สำหรับนักพัฒนา และอธิบายข้อตกลงของ request ครบถ้วน

/ ภาพรวม

หลักการทำงาน

คุณระบุที่อยู่รับข้อมูล (https://) และคีย์ลับไว้ที่ช่องทาง API ของโครงการ Orova จะส่ง request POST พร้อมเนื้อหาเป็น JSON ไปที่นั่น และแนบส่วนหัว X-Orova-Signature ซึ่งคือ HMAC-SHA256 ของไบต์ดิบของเนื้อหานั้น โดยใช้คีย์ลับของคุณ endpoint ของคุณตรวจลายเซ็น รับโพสต์ แล้วตอบกลับด้วยรหัส 2xx

  • ที่อยู่รับข้อมูลต้องเป็น https. ถ้าที่อยู่ไม่ใช่ https:// หรือไม่มีชื่อโฮสต์ Orova จะไม่บันทึกช่องทาง และแจ้งรหัส api_url
  • หนึ่งที่อยู่ หนึ่งช่องทาง. Orova ใช้ที่อยู่รับข้อมูลเป็นตัวระบุช่องทาง บันทึกที่อยู่เดิมซ้ำคือการเขียนทับช่องทางเดิม ไม่สร้างช่องทางซ้ำ
  • มีปุ่มส่งทดสอบ. เมื่อเชื่อมแล้ว ช่องทางจะมีปุ่ม Send test: Orova ยิงข้อมูล orova.test ไปที่ endpoint ของคุณทันที แล้วแสดงรหัส HTTP ที่ได้รับ พร้อมเวลาไป-กลับเป็นมิลลิวินาที

/ ตั้งค่า

ตั้งค่าใน Orova

เปิด Socialโครงการ → เลือกโครงการ → แท็บ ช่องทาง แล้วหากล่อง API ในนั้นมีช่องกรอกสองช่องและปุ่มหนึ่งปุ่ม

  • 1

    URL รับข้อมูล (webhook). ที่อยู่ endpoint ของคุณ ขึ้นต้นด้วย https:// ทุก request จะถูกส่งมาที่นี่

  • 2

    คีย์ลับ. สตริงที่ใช้ลงลายเซ็น ถ้าเว้นว่าง Orova จะสุ่มให้ แต่หน้าจอจะไม่แสดงซ้ำ จึงควรสร้างสตริงยาว ๆ เองแล้ววางลงไป และเก็บสำเนาไว้ฝั่งคุณ

  • 3

    กด Save channel. ช่องทางจะปรากฏในรายการพร้อมที่อยู่รับข้อมูล ส่วนคีย์ลับจะไม่แสดงอีก

  • 4

    กด Send test. Orova จะส่งข้อมูลตัวอย่าง orova.test ถ้า endpoint ตอบ 2xx Orova จะแจ้งว่า “Webhook ตอบ 200 ใน … ms” รหัสอื่นจะแจ้งพร้อมรหัสนั้น ส่วนกรณีติดต่อไม่ได้จะแจ้งเป็นข้อผิดพลาดเครือข่าย

/ ข้อตกลง

ข้อตกลงของ request

ทุกครั้งที่ส่ง request จะมีหน้าตาแบบนี้:

POST <your receiving URL>

Headers:
  Content-Type: application/json
  X-Orova-Signature: sha256=<hex HMAC-SHA256 of the raw body>
  X-Orova-Event: orova.test
  User-Agent: Orova-Social/1.0

Body (JSON):
  {
    "event": "orova.test",
    "workspace_id": 12,
    "project_id": 34,
    "post": {
      "title": "...",
      "content": "...",
      "media": [],
      "channels": ["api"]
    },
    "sent_at": "2026-08-23T01:25:00Z"
  }

เนื้อหาเป็น JSON UTF-8 แบบกระชับ บรรทัดเดียว ให้อ่านค่า event เพื่อแยกประเภท — ข้อมูลจากปุ่มส่งทดสอบมีค่า orova.test และส่วนหัว X-Orova-Event ก็เป็นค่าเดียวกัน endpoint ของคุณควรข้ามฟิลด์ที่ไม่รู้จักแทนที่จะปฏิเสธ เพื่อให้การเพิ่มฟิลด์ในอนาคตไม่ทำให้ระบบคุณพัง

ฟิลด์ชนิดคำอธิบาย
eventstringประเภทเหตุการณ์ ข้อมูลจากปุ่มส่งทดสอบคือ "orova.test"
workspace_idintegerไอดีพื้นที่ทำงานที่ส่งข้อมูลนี้
project_idinteger | nullไอดีโครงการที่ช่องทางสังกัด หรือ null ถ้ายังไม่ได้กำหนด
postobjectตัวโพสต์
post.titlestringหัวเรื่องของโพสต์
post.contentstringเนื้อหาโพสต์ในรูปข้อความ
post.mediaarrayไฟล์แนบของโพสต์ เป็นอาร์เรย์ว่างเมื่อมีแต่ข้อความ
post.channelsarray of stringประเภทช่องทางที่โพสต์นี้มุ่งไป เช่น ["api"]
sent_atstringเวลาที่ Orova ส่ง รูปแบบ ISO 8601 เวลา UTC ลงท้ายด้วย "Z"

/ การตรวจสอบ

ตรวจลายเซ็น

ส่วนหัว X-Orova-Signature อยู่ในรูป sha256=<hex> โดย <hex> คือ HMAC-SHA256 ของไบต์ดิบของเนื้อหา request ใช้คีย์ลับของช่องทาง ให้คำนวณซ้ำจากไบต์ที่ได้รับตรง ๆ — ถ้าแปลง JSON แล้วสร้างสตริงใหม่จะไม่ตรง เพราะต่างกันแค่ช่องว่างเดียวลายเซ็นก็เปลี่ยน

Node.js

// Node.js / Express — verify X-Orova-Signature, then answer fast
import express from "express";
import crypto from "node:crypto";

const app = express();
const OROVA_SECRET = process.env.OROVA_SECRET;   // the key you saved in Orova

// Keep the RAW bytes: the signature covers them, not re-serialized JSON.
app.post(
  "/orova/social",
  express.raw({ type: "application/json", limit: "5mb" }),
  (req, res) => {
    const sent = req.get("x-orova-signature") || "";
    const mine =
      "sha256=" +
      crypto.createHmac("sha256", OROVA_SECRET).update(req.body).digest("hex");

    // Constant-time compare — never use ===.
    const a = Buffer.from(sent);
    const b = Buffer.from(mine);
    if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
      return res.status(401).json({ error: "bad signature" });
    }

    const payload = JSON.parse(req.body.toString("utf8"));
    if (payload.event === "orova.test") {
      return res.status(200).json({ ok: true });   // the Send test button
    }

    // Real post: hand the work to a queue and reply straight away.
    queuePost(payload).catch(console.error);
    return res.status(200).json({ ok: true });
  },
);

app.listen(3000);

Python

# Python / Flask — same check, same rules
import hashlib
import hmac
import json
import os

from flask import Flask, request

app = Flask(__name__)
OROVA_SECRET = os.environ["OROVA_SECRET"].encode("utf-8")

@app.post("/orova/social")
def orova_social():
    raw = request.get_data()                       # bytes, exactly as sent
    mine = "sha256=" + hmac.new(OROVA_SECRET, raw, hashlib.sha256).hexdigest()
    sent = request.headers.get("X-Orova-Signature", "")
    if not hmac.compare_digest(mine, sent):        # constant-time compare
        return {"error": "bad signature"}, 401

    payload = json.loads(raw)
    if payload.get("event") == "orova.test":
        return {"ok": True}, 200

    queue_post(payload)                            # do the slow work later
    return {"ok": True}, 200

เปรียบเทียบด้วยฟังก์ชันแบบเวลาคงที่ (crypto.timingSafeEqual, hmac.compare_digest) อย่าใช้การเทียบเท่าธรรมดา ถ้าลายเซ็นไม่ตรงให้ตอบ 401 แล้วหยุด อย่าประมวลผลข้อมูลนั้น

/ การตอบกลับ

ตอบกลับอย่างไร

Orova ดูเฉพาะรหัสสถานะ HTTP รหัสในกลุ่ม 2xx ถือว่าสำเร็จ ส่วนเนื้อหาที่ตอบกลับจะเป็นอะไรก็ได้

  • ตอบให้เร็ว. ปุ่มส่งทดสอบรอไม่เกิน 10 วินาที งานหนัก เช่น ดาวน์โหลดไฟล์สื่อ หรือเรียก API ภายนอก ให้โยนเข้าคิวแล้วตอบ 2xx ทันที
  • Orova ไม่ลองส่งซ้ำเอง. เป็นความตั้งใจ เพราะการลองส่งซ้ำอัตโนมัติกับ API เผยแพร่คือต้นเหตุของการโพสต์ซ้ำสองครั้ง เมื่อส่งไม่สำเร็จ โพสต์จะถูกทำเครื่องหมาย failed พร้อมเหตุผล แล้วผู้ใช้กดเผยแพร่ใหม่ใน Orova
  • รองรับข้อมูลซ้ำได้. เมื่อผู้ใช้กดเผยแพร่ใหม่ ข้อมูลชุดเดิมจะมาอีกครั้ง ให้กรองซ้ำที่ฝั่งคุณ เช่น จำคู่ workspace_id กับ sent_at ที่จัดการไปแล้ว

/ ความปลอดภัย

ความปลอดภัย

  • ตรวจลายเซ็นเสมอ. endpoint ของคุณเป็น URL สาธารณะ ใครก็เรียกได้ ลายเซ็นคือสิ่งเดียวที่ยืนยันว่าข้อมูลมาจาก Orova จริง
  • อย่าเก็บคีย์ลับไว้ในโค้ด. เก็บไว้ในตัวแปรสภาพแวดล้อมหรือระบบจัดการความลับ อย่าเขียนตายตัวลงไฟล์ที่คุณ commit
  • เปลี่ยนคีย์ด้วยการบันทึกซ้ำ. กรอกที่อยู่รับข้อมูลเดิมพร้อมคีย์ใหม่แล้วกด Save channel — Orova จะเขียนทับช่องทางเดิม อย่าลืมอัปเดตฝั่ง endpoint ไปพร้อมกัน
  • ตัดการเชื่อมต่อคือลบคีย์. เมื่อคุณตัดการเชื่อมต่อช่องทาง Orova จะลบคีย์ลับที่เก็บไว้ และหยุดส่งข้อมูลไปที่อยู่นั้น

/ สรุป

ข้อตกลงมีเท่านี้

ที่อยู่ https หนึ่งที่ คีย์ลับหนึ่งอัน ตรวจลายเซ็นหนึ่งครั้ง และรหัส 2xx หนึ่งรหัส เท่านี้โพสต์จาก Orova Social ก็ไหลเข้าระบบของคุณ ส่วนที่เหลือ — จะเผยแพร่ต่อที่ไหน เก็บไว้ที่ใด บันทึกอย่างไร — คุณเป็นคนกำหนด

← กลับไปที่คลังคู่มือ

/ ต้องการความช่วยเหลือ

ติดขัดตอนต่อ endpoint ใช่ไหม เปิดส่วนสนับสนุนในพื้นที่ทำงานของคุณ หรือ ส่งข้อความถึงเรา