> ## Documentation Index
> Fetch the complete documentation index at: https://docs.so-me.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# পেলোডের ফরম্যাট ও যাচাইকরণ

> Social media studio কীভাবে ওয়েবহুক ইভেন্ট স্বাক্ষর ও ডেলিভারি করে, সাথে সাধারণ ইভেন্টের উদাহরণ পেলোড

Social media studio-র পাঠানো প্রতিটি ওয়েবহুক একই এনভেলপ ও স্বাক্ষর পদ্ধতি অনুসরণ করে। এই পেজে রিকোয়েস্টের হুবহু কাঠামো, সিগনেচার যাচাই করার পদ্ধতি এবং সাধারণ ইভেন্টের `data` ব্লক দেখতে কেমন তা দেখানো হয়েছে।

## রিকোয়েস্টের ফরম্যাট

### হেডার

প্রতিটি ডেলিভারিতে এই হেডারগুলো থাকে:

| হেডার | বিবরণ |
| - | - |
| `Content-Type` | `application/json` |
| `X-Webhook-Event` | ইভেন্টের নাম, যেমন `post.published` |
| `X-Webhook-Delivery-Id` | ডেলিভারি লগ সারির UUID, রিট্রাই ডিডুপ্লিকেট করতে কাজে লাগে |
| `X-Webhook-Signature` | কাঁচা রিকোয়েস্ট বডির HMAC-SHA256, হেক্স-এনকোডেড, আপনার এন্ডপয়েন্টের সিক্রেট দিয়ে স্বাক্ষরিত |

### এনভেলপ

কাস্টম `payloadTemplate` কনফিগার না করলে বডি হলো চারটি ফিল্ডের একটি JSON অবজেক্ট:

```json theme={null}
{
  "event": "post.published",
  "category": "post",
  "timestamp": "2026-04-22T14:30:00.000Z",
  "data": {
    "postId": "01J...",
    "platform": "instagram",
    "userId": "usr_..."
  }
}
```

* `event` — ইভেন্টের হুবহু নাম (`X-Webhook-Event`-এর সাথে মেলে)
* `category` — ইভেন্ট যে ক্যাটাগরির অন্তর্গত (যেমন `post`, `inbox`, `subscription`)
* `timestamp` — ইভেন্ট কখন পাঠানো হয়েছে তার ISO-8601 টাইমস্ট্যাম্প
* `data` — ইভেন্ট-নির্দিষ্ট পেলোড (নিচের উদাহরণ দেখুন)

> [!NOTE]
>
> রিট্রাইয়ে একই `X-Webhook-Delivery-Id` ব্যবহৃত হয়। এটিকে idempotency কী হিসেবে ব্যবহার করুন, যাতে রিট্রাই হওয়া ডেলিভারি আগেই সামলানো ইভেন্ট আবার প্রসেস না করে।

## Signature Verification

প্রতিটি রিকোয়েস্ট বডি আপনার এন্ডপয়েন্টের সিক্রেট দিয়ে HMAC-SHA256 ব্যবহার করে স্বাক্ষর করা হয়। ডেলিভারিটি সত্যিই Social media studio থেকে এসেছে তা নিশ্চিত করতে প্রতিটি রিকোয়েস্টে এটি যাচাই করুন।

> [!WARNING]
>
> JSON হিসেবে পার্স করার আগে সবসময় **কাঁচা রিকোয়েস্ট বডি** দিয়ে যাচাই করুন — পার্স করা অবজেক্ট আবার সিরিয়ালাইজ করলে হোয়াইটস্পেস বদলে যায় এবং সিগনেচার অবৈধ হয়ে যায়।

```javascript Node.js / Express theme={null}
import express from "express";
import crypto from "crypto";

const app = express();
const WEBHOOK_SECRET = process.env.SOMESTUDIO_WEBHOOK_SECRET;

app.post(
  "/webhook",
  express.raw({ type: "application/json" }),
  (req, res) => {
    const signature = req.header("X-Webhook-Signature");
    const expected = crypto
      .createHmac("sha256", WEBHOOK_SECRET)
      .update(req.body)
      .digest("hex");

    if (
      !signature ||
      !crypto.timingSafeEqual(
        Buffer.from(signature, "hex"),
        Buffer.from(expected, "hex"),
      )
    ) {
      return res.status(401).send("Invalid signature");
    }

    const payload = JSON.parse(req.body.toString("utf8"));
    console.log(payload.event, payload.data);

    res.status(200).send("ok");
  },
);

app.listen(3000);
```

```python Python / Flask theme={null}
import hmac
import hashlib
import os
from flask import Flask, request, abort

app = Flask(__name__)
WEBHOOK_SECRET = os.environ["SOMESTUDIO_WEBHOOK_SECRET"]

@app.post("/webhook")
def webhook():
    signature = request.headers.get("X-Webhook-Signature", "")
    expected = hmac.new(
        WEBHOOK_SECRET.encode(),
        request.get_data(),
        hashlib.sha256,
    ).hexdigest()

    if not hmac.compare_digest(signature, expected):
        abort(401)

    payload = request.get_json()
    print(payload["event"], payload["data"])
    return "ok", 200
```

```php PHP theme={null}
<?php
$secret    = getenv('SOMESTUDIO_WEBHOOK_SECRET');
$signature = $_SERVER['HTTP_X_WEBHOOK_SIGNATURE'] ?? '';
$body      = file_get_contents('php://input');
$expected  = hash_hmac('sha256', $body, $secret);

if (!hash_equals($expected, $signature)) {
    http_response_code(401);
    exit('Invalid signature');
}

$payload = json_decode($body, true);
error_log($payload['event']);

http_response_code(200);
echo 'ok';
```

```go Go theme={null}
package main

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "io"
    "net/http"
    "os"
)

var secret = []byte(os.Getenv("SOMESTUDIO_WEBHOOK_SECRET"))

func webhook(w http.ResponseWriter, r *http.Request) {
    body, _ := io.ReadAll(r.Body)
    defer r.Body.Close()

    mac := hmac.New(sha256.New, secret)
    mac.Write(body)
    expected := hex.EncodeToString(mac.Sum(nil))

    if !hmac.Equal([]byte(expected), []byte(r.Header.Get("X-Webhook-Signature"))) {
        http.Error(w, "Invalid signature", http.StatusUnauthorized)
        return
    }

    w.WriteHeader(http.StatusOK)
    w.Write([]byte("ok"))
}

func main() {
    http.HandleFunc("/webhook", webhook)
    http.ListenAndServe(":3000", nil)
}
```

## উদাহরণ পেলোড

`data` ব্লকের গঠন ইভেন্টের উপর নির্ভর করে। বহুল ব্যবহৃত ক্যাটাগরিগুলোর প্রতিনিধিত্বমূলক কিছু উদাহরণ এখানে দেওয়া হলো।

### পোস্ট

```json theme={null}
{
  "event": "post.published",
  "category": "post",
  "timestamp": "2026-04-22T14:30:00.000Z",
  "data": {
    "postId": "01JABC123...",
    "platform": "instagram",
    "userId": "usr_abc123"
  }
}
```

```json theme={null}
{
  "event": "post.failed",
  "category": "post",
  "timestamp": "2026-04-22T14:31:00.000Z",
  "data": {
    "postId": "01JABC123...",
    "platform": "twitter",
    "failureReason": "Social account session has expired"
  }
}
```

### অনুমোদন

```json theme={null}
{
  "event": "post.approval.approved",
  "category": "approval",
  "timestamp": "2026-04-22T14:32:00.000Z",
  "data": {
    "postId": "01JABC123...",
    "userId": "usr_abc123",
    "reviewerId": "mem_xyz789"
  }
}
```

### ইনবক্স

```json theme={null}
{
  "event": "inbox.message_received",
  "category": "inbox",
  "timestamp": "2026-04-22T14:33:00.000Z",
  "data": {
    "threadId": "thr_abc",
    "messageId": "msg_xyz",
    "platform": "instagram",
    "fromUser": { "id": "ig_456", "name": "Jane Doe" }
  }
}
```

### WhatsApp

```json theme={null}
{
  "event": "whatsapp.message_sent",
  "category": "whatsapp",
  "timestamp": "2026-04-22T14:33:30.000Z",
  "data": {
    "accountId": "15551234567",
    "to": "+15557654321",
    "templateName": "order_update",
    "messageId": "wamid.HBgM..."
  }
}
```

```json theme={null}
{
  "event": "whatsapp.template_created",
  "category": "whatsapp",
  "timestamp": "2026-04-22T14:33:45.000Z",
  "data": {
    "accountId": "15551234567",
    "name": "order_update",
    "language": "en_US",
    "category": "UTILITY"
  }
}
```

### সোশ্যাল অ্যাকাউন্ট

```json theme={null}
{
  "event": "account.token_expired",
  "category": "account",
  "timestamp": "2026-04-22T14:34:00.000Z",
  "data": {
    "accountId": "acc_123",
    "platform": "facebook",
    "postId": "01JABC123..."
  }
}
```

### সাবস্ক্রিপশন

`newPlanName` ফিল্ডে অভ্যন্তরীণ প্ল্যান শনাক্তকারী থাকে, যেমন Advanced-এর জন্য `scale`।

```json theme={null}
{
  "event": "subscription.upgraded",
  "category": "subscription",
  "timestamp": "2026-04-22T14:35:00.000Z",
  "data": {
    "subscriptionId": "lsq_sub_123",
    "newPlanId": "pln_scale",
    "newPlanName": "scale"
  }
}
```

### AI

```json theme={null}
{
  "event": "ai.image_generated",
  "category": "ai",
  "timestamp": "2026-04-22T14:36:00.000Z",
  "data": {
    "imageId": "img_abc",
    "userId": "usr_xyz",
    "prompt": "A sunset over the mountains",
    "url": "https://cdn.so-me.studio/..."
  }
}
```

### নলেজ হাব

```json theme={null}
{
  "event": "knowledge.created",
  "category": "knowledge",
  "timestamp": "2026-04-22T14:36:30.000Z",
  "data": {
    "id": "kn_abc123",
    "title": "Brand voice guide",
    "sourceType": "pdf",
    "isActive": true
  }
}
```

### অ্যানালিটিক্স

```json theme={null}
{
  "event": "analytics.report_generated",
  "category": "analytics",
  "timestamp": "2026-04-22T14:00:00.000Z",
  "data": {
    "generatedAt": "2026-04-22T14:00:00.000Z",
    "accountCount": 4,
    "windowHours": 2
  }
}
```

### সেরা সময়

```json theme={null}
{
  "event": "best_time.recommendation_recomputed",
  "category": "best_time",
  "timestamp": "2026-04-22T03:00:00.000Z",
  "data": {
    "socialAccountId": "acc_123",
    "platform": "instagram",
    "isPersonalized": true,
    "postCount": 87,
    "timezone": "America/New_York"
  }
}
```

### রেফারাল

```json theme={null}
{
  "event": "referral.reward_earned",
  "category": "referral",
  "timestamp": "2026-04-22T14:37:00.000Z",
  "data": {
    "referralId": "ref_abc",
    "userId": "usr_xyz",
    "role": "referrer",
    "creditsAwarded": 10
  }
}
```

> [!NOTE]
>
> ২৬টি ক্যাটাগরির ১৬২টি ইভেন্টের পূর্ণ তালিকার জন্য [ওয়েবহুক ওভারভিউ](/bn/webhooks/overview.md) দেখুন।

## কাস্টম পেলোড টেমপ্লেট

আপনার এন্ডপয়েন্ট ভিন্ন কাঠামো আশা করলে (যেমন Slack, Discord), ওয়েবহুক সাবস্ক্রিপশনে একটি `payloadTemplate` সেট করুন। ব্যবহারযোগ্য ভ্যারিয়েবল:

* `{{event}}`
* `{{category}}`
* `{{timestamp}}`
* `{{data}}` — সম্পূর্ণ data অবজেক্ট JSON হিসেবে
* `{{data.any_field}}` — ইভেন্ট-নির্দিষ্ট পেলোডের যেকোনো নেস্টেড ফিল্ড

যে ভ্যারিয়েবলের মান পাওয়া যায় না তা যেমন আছে তেমনই থাকে (যেমন ইভেন্টে `postId` না থাকলে `{{data.postId}}` লিটারেল থাকে)। Discord ও Slack টেমপ্লেটের উদাহরণের জন্য ওভারভিউ পেজ দেখুন।

## লোকালি পরীক্ষা করা

ডেভেলপমেন্টের সময়:

1. আপনার লোকাল সার্ভার উন্মুক্ত করতে [ngrok](https://ngrok.com/) বা [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/)-এর মতো টানেলিং টুল ব্যবহার করুন।
2. **সেটিংস → ওয়েবহুক**-এ আপনার টানেল URL-এর দিকে নির্দেশ করে একটি ওয়েবহুক সাবস্ক্রিপশন তৈরি করুন।
3. আসল কার্যকলাপ না ঘটিয়ে নমুনা ইভেন্ট পাঠাতে সাবস্ক্রিপশনের **টেস্ট ইভেন্ট পাঠান** বোতামে ক্লিক করুন।
4. ভেরিফায়ার লেখার আগে কাঁচা রিকোয়েস্ট দেখতে চাইলে [Webhook.site](https://webhook.site/)-এ পেলোড পরীক্ষা করুন।

> [!WARNING]
>
> আপনার এন্ডপয়েন্ট **টানা ১০টি ডেলিভারিতে** ব্যর্থ হলে সাবস্ক্রিপশন স্বয়ংক্রিয়ভাবে নিষ্ক্রিয় হয়ে যায়। সমস্যা ঠিক করার পর ড্যাশবোর্ড থেকে এটি আবার সক্রিয় করুন।


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.