/ Hướng dẫn cho lập trình viên
Nhận bài đăng từ Orova Social qua Webhook.
Cách dựng một endpoint nhận bài Orova Social gửi sang, và xác minh chữ ký trước khi xử lý.
Orova Social đăng thẳng lên các nền tảng đã nối sẵn. Muốn đưa bài đến một nơi khác — kênh nội bộ, ứng dụng của bạn, một nền tảng Orova chưa hỗ trợ — bạn dùng kênh API: Orova gửi bài sang một địa chỉ HTTP của bạn, ký bằng khoá bí mật, và bạn tự làm phần còn lại. Trang này dành cho lập trình viên và mô tả đủ hợp đồng request.
/ Tổng quan
Cách hoạt động
Bạn khai một địa chỉ nhận bài (https://) và một khoá bí mật cho kênh API của dự án. Orova gửi tới đó một request POST với thân JSON, kèm header X-Orova-Signature — chữ ký HMAC-SHA256 tính trên đúng chuỗi byte của thân request bằng khoá bí mật đó. Endpoint của bạn kiểm chữ ký, nhận bài, rồi trả về mã 2xx.
- Địa chỉ nhận bài phải là https. Orova từ chối lưu kênh nếu địa chỉ không phải
https://hoặc thiếu tên miền — báo mãapi_url. - Một kênh API cho mỗi địa chỉ. Orova nhận diện kênh theo chính địa chỉ nhận bài. Lưu lại cùng một địa chỉ là ghi đè kênh cũ, không đẻ thêm kênh trùng.
- Có nút Gửi thử. Kênh nối xong có nút Gửi thử: Orova bắn ngay một gói
orova.testsang endpoint của bạn và hiện lại mã HTTP kèm thời gian trả lời tính bằng mili giây.
/ Cài đặt
Thiết lập trong Orova
Mở Social → Dự án → chọn dự án → tab Kênh, rồi tìm ô API. Ô này có hai chỗ nhập và một nút.
- 1
URL nhận bài (webhook). Địa chỉ endpoint của bạn, bắt đầu bằng
https://. Đây là nơi Orova gửi mọi request. - 2
Mã bí mật. Chuỗi dùng để ký. Để trống thì Orova tự sinh một chuỗi ngẫu nhiên — nhưng màn hình không hiện lại mã đó, nên hãy tự sinh một chuỗi dài rồi dán vào, và cất bản sao ở phía bạn.
- 3
Bấm Save channel. Kênh hiện ngay trong danh sách kèm địa chỉ nhận bài. Mã bí mật không bao giờ hiện lại trên màn hình.
- 4
Bấm Gửi thử. Orova gửi một gói mẫu
orova.test. Endpoint trả về mã 2xx thì Orova báo “Webhook trả về 200 sau … ms”. Trả mã khác thì báo lỗi kèm mã đó; không gọi tới được thì báo lỗi mạng.
/ Hợp đồng
Hợp đồng request
Mỗi lần gửi, Orova bắn sang một request có dạng như sau:
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"
}Thân request là JSON UTF-8 gọn, không xuống dòng. Hãy đọc event để biết loại sự kiện — gói của nút Gửi thử mang orova.test, và header X-Orova-Event lặp lại đúng giá trị đó. Endpoint nên bỏ qua trường lạ thay vì báo lỗi, để phần mở rộng sau này không làm hỏng phía bạn.
| Trường | Kiểu | Mô tả |
|---|---|---|
| event | string | Loại sự kiện. Gói của nút Gửi thử là "orova.test". |
| workspace_id | integer | ID khu làm việc gửi gói này. |
| project_id | integer | null | ID dự án chứa kênh, hoặc null nếu kênh chưa gán dự án. |
| post | object | Nội dung bài đăng. |
| post.title | string | Tiêu đề bài. |
| post.content | string | Thân bài dạng chữ. |
| post.media | array | Danh sách tệp đính kèm của bài; mảng rỗng khi bài chỉ có chữ. |
| post.channels | array of string | Các loại kênh mà bài này nhắm tới, ví dụ ["api"]. |
| sent_at | string | Thời điểm Orova gửi, chuẩn ISO 8601 theo giờ UTC, kết thúc bằng "Z". |
/ Xác minh
Xác minh chữ ký
Header X-Orova-Signature có dạng sha256=<hex>, trong đó <hex> là HMAC-SHA256 của chuỗi byte thô của thân request, khoá là mã bí mật của kênh. Hãy tính lại chữ ký trên đúng chuỗi byte nhận được — đọc JSON ra rồi tạo chuỗi lại là sai, vì chỉ cần lệch một dấu cách là chữ ký khác.
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}, 200So chữ ký bằng hàm so sánh hằng thời gian (crypto.timingSafeEqual, hmac.compare_digest), đừng dùng phép so bằng thường. Chữ ký không khớp thì trả 401 và dừng — đừng xử lý gói đó.
/ Trả lời
Trả lời thế nào
Orova chỉ nhìn mã trạng thái HTTP. Mọi mã trong nhóm 2xx là thành công; thân response bạn trả gì cũng được.
- Trả lời nhanh. Nút Gửi thử chờ tối đa
10 giây. Việc nặng — tải ảnh, gọi API bên thứ ba — hãy đẩy vào hàng đợi rồi trả 2xx ngay. - Orova không tự thử lại. Đây là chủ ý: tự thử lại với API đăng bài dễ làm bài lên hai lần. Lần gửi hỏng thì bài bị đánh dấu
failedkèm lý do, và người dùng bấm đăng lại trong Orova. - Nên chịu được gói trùng. Người dùng bấm đăng lại là gói cũ đi lại lần nữa. Hãy tự khử trùng lặp ở phía bạn — ví dụ nhớ lại cặp
workspace_id+sent_atđã xử lý.
/ Bảo mật
Bảo mật
- Luôn kiểm chữ ký. Endpoint của bạn là một URL công khai — ai cũng gọi được. Chữ ký là thứ duy nhất chứng minh gói tin thật sự đến từ Orova.
- Giữ mã bí mật ngoài mã nguồn. Cất ở biến môi trường hoặc kho bí mật, đừng viết cứng vào file rồi commit.
- Đổi mã bí mật bằng cách lưu lại. Nhập lại chính địa chỉ nhận bài đó kèm mã mới rồi bấm Save channel — Orova ghi đè kênh cũ. Đổi xong nhớ cập nhật luôn phía endpoint.
- Ngắt kênh là xoá mã. Bấm ngắt kênh thì Orova xoá mã bí mật đã lưu, và không gửi gì sang địa chỉ đó nữa.
/ Khép lại
Hợp đồng chỉ có vậy
Một địa chỉ https, một mã bí mật, một lần kiểm chữ ký và một mã 2xx — đủ để bài từ Orova Social chảy về hệ thống của bạn. Phần còn lại là việc của bạn: đăng tiếp đi đâu, lưu ở đâu, ghi sổ thế nào.
/ Cần hỗ trợ?
Nối endpoint mãi chưa được? Mở mục Hỗ trợ trong khu làm việc, hoặc gửi tin nhắn cho chúng tôi.
