🏠 Home ← Docs Index
Open Beta 📖 Interactive Reader Raw .md llms.txt

Webhook Audit Logging

Webhook audit logging records semantic channel events in memory so operators can inspect recent activity from the Web UI. It is designed for real-time visibility, not long-term forensic storage.

Data Flow

flowchart TD
    CH["<b>Channels</b><br/>Discord / Teams / Facebook / Telegram"] --> H["<b>Channel Handler</b>"]
    H --> REC["<b>runtimeinfo.RecordWebhookAudit</b>"]
    REC --> BUF["<b>runtimeinfo.WebhookAuditLogs</b><br/>In-memory ring buffer (newest 500)"]
    BUF --> API["<b>GET /api/audit</b>"]

Data Structure

type WebhookAuditLog struct {
    Timestamp  time.Time `json:"timestamp"`
    Channel    string    `json:"channel"`
    EventType  string    `json:"event_type"`
    AuthorID   string    `json:"author_id"`
    AuthorName string    `json:"author_name"`
    PeerID     string    `json:"peer_id"`
    PeerKind   string    `json:"peer_kind"`
    Preview    string    `json:"preview"`
    Status     string    `json:"status"`
}

RecordWebhookAudit sets Timestamp when missing, cuts Preview to its first 120 bytes followed by …, and keeps only the newest 500 records. The buffer is in memory: a restart empties it.

Status is processed, error (handling or answering the message failed), duplicate (a repeated Teams delivery that was ignored), ignored, or, for a Teams SSO attempt, unimplemented.

Event Types

Event type Meaning
chat Regular text message
command Slash command or command-style message
typing Typing indicator, usually ignored
reaction Message reaction, usually ignored
comment Conversation update or comment-style event
login_attempt Teams SSO token exchange (recorded with channel msteams_sso)
unknown Channel event that did not match a known class

API

GET /api/audit?channel=facebook&event=chat&user=USER123&limit=50

All query parameters are optional.

Parameter Description
channel Filter by channel: discord, msteams, msteams_sso, facebook or telegram
event Filter by event type
user Filter by author ID
limit Maximum rows, 1 to 500 (default 100). A missing, invalid, zero, negative or larger value gives 100

Response:

{
  "logs": [
    {
      "timestamp": "2026-06-20T08:45:00Z",
      "channel": "discord",
      "event_type": "chat",
      "author_id": "123456789",
      "author_name": "User",
      "peer_id": "987654321",
      "peer_kind": "direct",
      "preview": "Hello, can you help me?",
      "status": "processed"
    }
  ],
  "total": 1
}

Recording Points

File Event source
internal/channel/discord/discord_handler.go Discord messages
internal/channel/discord/discord_slash.go Discord slash commands
internal/channel/msteams/msteams.go Teams activities
internal/channel/msteams/msteams_sso.go Teams SSO token exchange attempts (channel msteams_sso, event login_attempt)
internal/channel/facebook/facebook.go Facebook messages
internal/channel/telegram/telegram.go Telegram messages

Audit Lines in the Gateway Log

A separate trail, internal/audit, records destructive or administrative actions as one line each in the gateway log:

[audit] action=sop.delete actor=… role=… source=… ip=… resource=sop/<id> success=true

It is written for sop.delete (from the sop tool and the SOP API) and for sop.channel.pin / sop.channel.unpin (the SOP channels API). Find them with grep '\[audit\]' gateway.log. The last 500 are also kept in memory and served by GET /api/audit?kind=admin, newest first, filtered by ?action=, ?actor= and ?resource= (a resource type such as sop) and limited by ?limit= (default 100); they do not survive a restart.

Tests

go test ./internal/runtimeinfo -count=1

The runtimeinfo tests cover recording, timestamp defaults, preview truncation, ring buffer overflow, filters, and newest-first ordering.