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

# Event Stream → Real-Time Persona Triggers

> Configure Segment webhook destinations to automatically create Mavera personas or trigger research when user behavior changes in real time

### Scenario

Segment sends events in real time to destinations — including webhooks. You configure a Segment webhook destination to send specific events (like `trial_started`, `plan_upgraded`, `feature_milestone`) to your server, which automatically creates or updates a Mavera persona or triggers a Mave research query. The result is research that triggers in real time when user behavior changes, not on a batch schedule.

### Architecture

```mermaid theme={"dark"}
flowchart LR
A["Segment source track() events"] --> B["Webhook destination"] --> C["Your server"] --> D["POST /api/v1/personas or /mave/chat"] --> E["Auto-triggered research"]
```

### Code

<CodeGroup>
  ```python Python theme={"dark"}
  import os, requests, json, time
  from http.server import HTTPServer, BaseHTTPRequestHandler

  MV = os.environ["MAVERA_API_KEY"]
  MB = "https://app.mavera.io/api/v1"
  MH = {"Authorization": f"Bearer {MV}", "Content-Type": "application/json"}

  TRIGGER_EVENTS = {
      "trial_started": {
          "action": "create_persona",
          "persona_template": {
              "name_prefix": "Segment RT: Trial User",
              "description_template": "Real-time persona created when user {user_id} started a trial. Plan: {plan}. Source: {source}.",
          },
      },
      "plan_upgraded": {
          "action": "research",
          "research_template": "A user just upgraded from {previous_plan} to {new_plan}. Research: What motivates users to upgrade at this point in their journey? What features do they expect immediately after upgrading? What's the #1 risk of churn in the first 7 days post-upgrade?",
      },
      "feature_milestone": {
          "action": "create_persona",
          "persona_template": {
              "name_prefix": "Segment RT: Feature Champion",
              "description_template": "Power user who reached {milestone} milestone for feature {feature_name}. This user has deeply adopted {feature_name}.",
          },
      },
      "churn_signal": {
          "action": "research",
          "research_template": "A user with LTV ${ltv} just triggered a churn signal: {signal_type}. They've been a customer for {tenure_days} days. Research: What retention intervention works best for users at this LTV and tenure? Draft 3 personalized re-engagement messages.",
      },
  }

  class WebhookHandler(BaseHTTPRequestHandler):
      def do_POST(self):
          length = int(self.headers.get("Content-Length", 0))
          body = json.loads(self.rfile.read(length)) if length else {}

          event_type = body.get("event", body.get("type", ""))
          properties = body.get("properties", {})
          traits = body.get("traits", body.get("context", {}).get("traits", {}))
          user_id = body.get("userId", body.get("anonymousId", "unknown"))

          merged = {**properties, **traits, "user_id": user_id}

          if event_type in TRIGGER_EVENTS:
              config = TRIGGER_EVENTS[event_type]
              print(f"\n[TRIGGER] {event_type} from user {user_id}")

              if config["action"] == "create_persona":
                  tmpl = config["persona_template"]
                  name = f"{tmpl['name_prefix']} — {user_id[:12]}"
                  desc = tmpl["description_template"].format(**{k: merged.get(k, "unknown") for k in ["user_id", "plan", "source", "milestone", "feature_name"]})

                  persona = requests.post(f"{MB}/personas", headers=MH, json={
                      "name": name,
                      "description": desc,
                      "psychographic": {"trigger_event": event_type, **{k: v for k, v in merged.items() if isinstance(v, (str, int, float))}},
                  }).json()
                  print(f"  Created persona: {persona.get('id')} — {name}")

              elif config["action"] == "research":
                  safe_vals = {k: str(merged.get(k, "unknown")) for k in ["previous_plan", "new_plan", "ltv", "signal_type", "tenure_days"]}
                  message = config["research_template"].format(**safe_vals)

                  mave = requests.post(f"{MB}/mave/chat", headers=MH, json={"message": message}).json()
                  print(f"  Research result: {mave.get('content', '')[:200]}")

          self.send_response(200)
          self.end_headers()
          self.wfile.write(b'{"status":"ok"}')

      def log_message(self, format, *args):
          pass

  PORT = int(os.environ.get("WEBHOOK_PORT", "8080"))
  print(f"Listening for Segment webhooks on port {PORT}")
  print(f"Trigger events: {', '.join(TRIGGER_EVENTS.keys())}")
  server = HTTPServer(("0.0.0.0", PORT), WebhookHandler)
  server.serve_forever()
  ```

  ```javascript JavaScript theme={"dark"}
  const MV = process.env.MAVERA_API_KEY;
  const MB = "https://app.mavera.io/api/v1";
  const MH = { Authorization: `Bearer ${MV}`, "Content-Type": "application/json" };

  const TRIGGERS = {
    trial_started: {
      action: "create_persona",
      namePrefix: "Segment RT: Trial User",
      descTemplate: (d) => `Trial started by ${d.user_id}. Plan: ${d.plan || "unknown"}. Source: ${d.source || "unknown"}.`,
    },
    plan_upgraded: {
      action: "research",
      msgTemplate: (d) => `User upgraded from ${d.previous_plan || "free"} to ${d.new_plan || "paid"}. Research: upgrade motivations, expected features, churn risk in first 7 days post-upgrade.`,
    },
    feature_milestone: {
      action: "create_persona",
      namePrefix: "Segment RT: Feature Champion",
      descTemplate: (d) => `Power user reached ${d.milestone || "unknown"} milestone for ${d.feature_name || "unknown"}.`,
    },
    churn_signal: {
      action: "research",
      msgTemplate: (d) => `Churn signal from user with LTV $${d.ltv || 0}: ${d.signal_type || "unknown"}. Tenure: ${d.tenure_days || 0} days. Research retention interventions + 3 re-engagement messages.`,
    },
  };

  const http = await import("http");
  const PORT = parseInt(process.env.WEBHOOK_PORT || "8080");

  const server = http.createServer(async (req, res) => {
    if (req.method !== "POST") { res.writeHead(405); res.end(); return; }

    let body = "";
    for await (const chunk of req) body += chunk;
    const data = JSON.parse(body || "{}");

    const eventType = data.event || data.type || "";
    const merged = { ...(data.properties || {}), ...(data.traits || {}), user_id: data.userId || data.anonymousId || "unknown" };

    if (TRIGGERS[eventType]) {
      const cfg = TRIGGERS[eventType];
      console.log(`\n[TRIGGER] ${eventType} from ${merged.user_id}`);

      if (cfg.action === "create_persona") {
        const name = `${cfg.namePrefix} — ${merged.user_id.slice(0, 12)}`;
        const p = await fetch(`${MB}/personas`, { method: "POST", headers: MH,
          body: JSON.stringify({
            name, description: cfg.descTemplate(merged),
            psychographic: { trigger_event: eventType },
          }),
        }).then((r) => r.json());
        console.log(`  Created persona: ${p.id}`);
      } else {
        const mave = await fetch(`${MB}/mave/chat`, { method: "POST", headers: MH,
          body: JSON.stringify({ message: cfg.msgTemplate(merged) }),
        }).then((r) => r.json());
        console.log(`  Research: ${(mave.content || "").slice(0, 200)}`);
      }
    }

    res.writeHead(200, { "Content-Type": "application/json" });
    res.end('{"status":"ok"}');
  });

  server.listen(PORT, () => {
    console.log(`Listening for Segment webhooks on port ${PORT}`);
    console.log(`Triggers: ${Object.keys(TRIGGERS).join(", ")}`);
  });
  ```
</CodeGroup>

### Example Output

```text theme={"dark"}
Listening for Segment webhooks on port 8080
Triggers: trial_started, plan_upgraded, feature_milestone, churn_signal

[TRIGGER] trial_started from user usr_k8m2n
  Created persona: per_rt_trial_1 — Segment RT: Trial User — usr_k8m2n

[TRIGGER] plan_upgraded from user usr_p4x9q
  Research: Users who upgrade typically do so after experiencing a
  "capacity moment" — they hit a limit (storage, team seats, API
  calls) that blocks a workflow they've already committed to. The
  #1 feature expectation post-upgrade is immediate access to the
  capability that triggered the upgrade, not a welcome tour of all
  premium features. Churn risk in days 1-7 is highest when...

[TRIGGER] churn_signal from user usr_r7w3t
  Research: For users with LTV in the $200-500 range and 90+ day
  tenure, the most effective retention intervention is a personal
  outreach from a CSM (not automated email). The message should
  acknowledge their specific usage pattern and offer a concrete
  next step...
```

### Error Handling

<AccordionGroup>
  <Accordion title="Webhook destination setup">In Segment, add a Webhook destination: Destinations → Add Destination → Webhooks → Configure. Set the URL to your server's public endpoint. Enable the specific events you want to trigger on.</Accordion>
  <Accordion title="Webhook authentication">Segment webhook destinations support shared secrets. Add a `x-segment-secret` header check in your handler to verify requests originate from Segment.</Accordion>
  <Accordion title="Idempotency">Segment may retry failed webhook deliveries. Use the `messageId` field to deduplicate — store processed message IDs and skip duplicates to avoid creating duplicate personas.</Accordion>
  <Accordion title="Public URL requirement">The webhook server needs a public URL. For development, use `ngrok`, `cloudflare tunnel`, or deploy to a serverless platform (AWS Lambda, Vercel, etc.).</Accordion>
</AccordionGroup>

***

## What's Next

<CardGroup cols={2}>
  <Card title="Segment Integration" icon="diagram-project" href="/integrations/segment">
    Back to Segment integration overview
  </Card>

  <Card title="Profile Traits → Custom Persona Source" icon="user-gear" href="/integrations/segment/profile-traits-personas">
    Create trait-enriched personas from computed traits
  </Card>

  <Card title="Cross-Source Unified Persona" icon="circle-nodes" href="/integrations/segment/cross-source-unified-persona">
    Build unified cross-channel personas
  </Card>

  <Card title="Mave Agent" icon="brain" href="/api-reference/mave">
    Full reference for POST /api/v1/mave/chat
  </Card>
</CardGroup>
