OROVA.VN — BIZ AI AGENT

/ Guide pour développeurs

Recevoir les publications d'Orova Social par webhook.

Comment créer un endpoint qui reçoit les publications envoyées par Orova Social, et vérifier la signature avant de les traiter.

Orova Social publie directement sur les plateformes qu'il connecte. Quand une publication doit aller ailleurs — un canal interne, votre propre application, une plateforme pas encore prise en charge — vous utilisez le canal API : Orova envoie la publication à une adresse HTTP à vous, signée avec une clé secrète, et la suite vous appartient. Ce guide s'adresse à un développeur et décrit tout le contrat de requête.

/ Vue d'ensemble

Comment ça marche

Vous déclarez une adresse de réception (https://) et une clé secrète sur le canal API de votre projet. Orova y envoie une requête POST avec un corps JSON et un en-tête X-Orova-Signature : le HMAC-SHA256 des octets exacts de ce corps, avec votre clé. Votre endpoint vérifie la signature, récupère la publication, puis renvoie un statut 2xx.

  • L'adresse de réception doit être en https. Orova refuse d'enregistrer le canal si l'adresse n'est pas en https:// ou n'a pas d'hôte : il renvoie le code api_url.
  • Un canal par adresse. Orova identifie le canal par l'adresse de réception elle-même. Enregistrer la même adresse écrase le canal existant au lieu d'en créer un doublon.
  • Il y a un bouton Envoyer un test. Une fois connecté, le canal affiche un bouton Send test : Orova envoie un paquet orova.test à votre endpoint et vous montre le statut HTTP reçu ainsi que l'aller-retour en millisecondes.

/ Mise en place

Configuration dans Orova

Ouvrez SocialProjets → votre projet → onglet Canaux, puis repérez le bloc API. Il contient deux champs et un bouton.

  • 1

    URL de réception (webhook). L'adresse de votre endpoint, commençant par https://. C'est là qu'arrivent toutes les requêtes.

  • 2

    Clé secrète. La chaîne qui sert à signer. Laissée vide, Orova en génère une au hasard — mais l'écran ne la réaffiche jamais : générez vous-même une chaîne longue, collez-la, et gardez votre copie.

  • 3

    Cliquez sur Save channel. Le canal apparaît dans la liste avec son adresse de réception. La clé n'est plus jamais affichée.

  • 4

    Cliquez sur Send test. Orova envoie un paquet d'exemple orova.test. Si votre endpoint répond 2xx, Orova indique « Le webhook a répondu 200 en … ms ». Tout autre statut est signalé avec son code ; un endpoint injoignable est signalé comme erreur réseau.

/ Contrat

Contrat de la requête

Chaque envoi arrive sous la forme d'une requête comme celle-ci :

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"
  }

Le corps est du JSON UTF-8 compact, sur une seule ligne. Lisez event pour distinguer les types : le paquet du bouton de test porte orova.test, et l'en-tête X-Orova-Event reprend la même valeur. Votre endpoint devrait ignorer les champs inconnus plutôt que les rejeter, pour que des ajouts ultérieurs ne cassent rien chez vous.

ChampTypeDescription
eventstringLe type d'événement. Le paquet de test vaut "orova.test".
workspace_idintegerIdentifiant de l'espace de travail à l'origine de l'envoi.
project_idinteger | nullIdentifiant du projet qui porte le canal, ou null si le canal n'en a pas.
postobjectLa publication elle-même.
post.titlestringLe titre de la publication.
post.contentstringLe corps de la publication, en texte.
post.mediaarrayLes pièces jointes de la publication ; tableau vide si elle n'a que du texte.
post.channelsarray of stringLes types de canaux visés, par exemple ["api"].
sent_atstringLe moment de l'envoi, ISO 8601 en UTC, terminé par "Z".

/ Vérification

Vérifier la signature

L'en-tête X-Orova-Signature s'écrit sha256=<hex>, où <hex> est le HMAC-SHA256 des octets bruts du corps, avec la clé du canal. Recalculez-le sur exactement les octets reçus : analyser le JSON puis le re-sérialiser ne correspondra pas, car une seule espace de différence change la signature.

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

Comparez avec une fonction à temps constant (crypto.timingSafeEqual, hmac.compare_digest), jamais avec une simple égalité. Si la signature ne correspond pas, renvoyez 401 et arrêtez-vous : ne traitez pas ce paquet.

/ Réponse

Comment répondre

Orova ne regarde que le statut HTTP. Tout code 2xx vaut succès ; le corps de la réponse est libre.

  • Répondez vite. Le bouton Send test attend 10 secondes au maximum. Mettez le travail lent — téléchargement de médias, appel d'une API tierce — dans une file, et renvoyez 2xx tout de suite.
  • Orova ne réessaie jamais tout seul. C'est volontaire : les tentatives automatiques sur une API de publication sont la cause classique des doublons. Un envoi en échec marque la publication failed avec la raison, et la personne relance depuis Orova.
  • Sachez encaisser un doublon. Quand quelqu'un relance, le même paquet revient. Faites la déduplication chez vous, par exemple en mémorisant les couples workspace_id et sent_at déjà traités.

/ Sécurité

Sécurité

  • Vérifiez toujours la signature. Votre endpoint est une URL publique : n'importe qui peut l'appeler. La signature est la seule chose qui prouve qu'un paquet vient bien d'Orova.
  • Gardez la clé hors du code. Stockez-la dans une variable d'environnement ou un gestionnaire de secrets, jamais en dur dans un fichier versionné.
  • Changez la clé en réenregistrant. Saisissez la même adresse de réception avec la nouvelle clé et cliquez sur Save channel : Orova écrase le canal existant. Mettez votre endpoint à jour en même temps.
  • Déconnecter supprime la clé. À la déconnexion du canal, Orova efface la clé enregistrée et n'envoie plus rien à cette adresse.

/ Pour finir

Voilà tout le contrat

Une adresse https, une clé, une vérification de signature et un statut 2xx : c'est tout ce qu'il faut pour que les publications d'Orova Social arrivent dans vos systèmes. La suite vous appartient : où elles sont publiées, où elles sont stockées, comment elles sont journalisées.

← Retour à la bibliothèque de guides

/ Besoin d'aide ?

Bloqué sur votre endpoint ? Ouvrez la section Support dans votre espace de travail, ou écrivez-nous.