Audit log streaming
Send your org's audit log (role, channel, member and integration changes) to your own server or SIEM as it happens, signed so the receiver can check each delivery came from Missived.
Before you start
- Who: adding and managing audit destinations needs the Manage integrations permission (Owners, Admins, or a custom role that grants it). Reading the audit log, in the app or over the API, is for Owners and Admins.
- Plans: every plan, with a number of destinations per org: Free 1, Ministry 2, Creator 2, Business 10.
- Your receiver must be an
https://URL on the public internet. Private and internal addresses are refused when you save and again on every delivery, and redirects are not followed.
Audit destinations carry audit events (who changed what in the org). For product events such as messages, members joining or meetings, use event subscriptions instead.
The audit log in the app
Org Settings → Audit log lists the org's most recent events, newest first: when, the action (such as channel.deleted), who did it and what it was done to. Filter by an exact action name and press Refresh. Actions taken in your org by a Missived platform admin carry a platform badge.
Add a destination
- Open Org Settings → Integrations → Outgoing webhooks → Add outgoing webhook.
- Fill in:
| Field | What it does |
|---|---|
| Name (optional) | A label, such as "Splunk production" |
| URL | Where deliveries are POSTed. https only, public addresses only. |
| Format | OCSF: the Open Cybersecurity Schema Framework (1.8.0) envelope most SIEMs read. Simple JSON: Missived's own flat shape. |
| Which events | A minimum severity: Everything (informational and up), Low and up, Medium and up, High and up, or Critical only |
| Only these actions (optional) | Action names separated by commas; * matches the rest of a name (role.*, channel.deleted). Empty sends every action. |
| Extra header / Header value (optional) | A fixed header for a gateway that wants a token, such as Authorization: Bearer …. Stored encrypted and never shown again. |
| Also sign with Ed25519 | Adds an Ed25519 signature the receiver checks with a public key instead of the shared secret |
- Add webhook. Copy the signing secret (
whsec_…) and, if you chose Ed25519, the public key (whpk_…, not secret). The secret is shown only now. - Choose Send test to send a signed test event. The page shows the request and your receiver's answer.
To change the extra header or the signing type later, add a new destination and delete the old one. The list of action names is at listAuditActions.
What a delivery looks like
Each audit event is one POST:
POST /your/url
content-type: application/json
user-agent: Missived-Webhooks/1.0
webhook-id: 0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6b
webhook-timestamp: 1761480000
webhook-signature: v1,<base64 HMAC-SHA256>
With Simple JSON the body is:
{
"id": "0192a3b4-5c6d-7e8f-9a0b-1c2d3e4f5a6b",
"seq": 4182,
"occurred_at": "2026-10-26T12:00:00.000Z",
"action": "channel.deleted",
"outcome": "success",
"org_id": "…",
"actor": { "type": "user", "id": "…", "label": "[email protected]", "on_behalf_of": null },
"target": { "type": "channel", "id": "…", "label": "old-announcements" },
"metadata": { }
}
With OCSF the body is the OCSF envelope: class_uid, category_uid, activity_id, type_uid, severity_id (1 to 6), time (milliseconds), status / status_id, metadata.version and metadata.product, actor.user (uid, name, type), resource (the target), and unmapped with the Missived action, org_id and the event's metadata. The classes in use are Account Change (3001), Authentication (3002), Entity Management (3004), User Access Management (3005) and API Activity (6003). getAuditSchemas describes the shape.
webhook-idis the event'sid. It is the same on every retry and replay, so use it to drop duplicates.actor.typeisuser,service(an app or token),platform_adminorsystem.seqincreases per org. Deliveries can arrive out of order; sort byseqif order matters.- A test delivery has the action
webhook.testand an id startingevt_test_.
Verify the signature
Deliveries follow Standard Webhooks, so any Standard Webhooks library verifies them. By hand:
- Take
webhook-id,webhook-timestampand the raw body exactly as received, before parsing. - Reject a timestamp more than 5 minutes from now.
- Compute HMAC-SHA256 over
"{webhook-id}.{webhook-timestamp}.{raw body}", keyed with the base64-decoded part of the secret afterwhsec_, and base64-encode it. webhook-signatureis a space-separated list. Accept the delivery if anyv1,entry matches (compare in constant time).
The same code as for event subscriptions works unchanged.
Ed25519. When it's on, the list also holds a v1a,<base64 signature> entry: an Ed25519 signature over the same "{id}.{timestamp}.{body}" string. The public key is whpk_ followed by a base64 DER (SPKI) key. A receiver that verifies with the public key holds nothing that could forge a delivery.
Extra header. If you set one, it arrives on every delivery as given. It is not a signature; check the signature too.
Rotating the secret
Rotate secret issues a new whsec_ secret (shown once). Until you rotate again, deliveries carry a v1 signature for the new secret and one for the old, so a receiver with either keeps working while you update it.
Retries, pauses and 410
Delivery is at least once.
- A 2xx answer within 10 seconds is success.
- A 5xx, 408, 429, a timeout or a network error is retried with exponential backoff and jitter (starting around 10 seconds, at most an hour apart) for up to 24 hours.
Retry-Afteris honoured. - Any other 4xx is a configuration problem and is not retried.
- After 20 failed deliveries in a row, the destination pauses itself.
- 410 Gone switches it off at once: the receiver doesn't want these events any more.
A paused or switched-off destination says why on the Integrations page. Resume turns it back on and resets the failure count. Pause stops deliveries until you resume.
Delivery log and replay
Each destination shows its health (deliveries and failures in the last 24 hours) and a delivery log with each delivery's status, attempts, your receiver's response code and the start of its answer.
- Replay on a row sends that delivery again, with the same
webhook-id. - Replay 24h sends the last 24 hours' matching events again. Same ids, so a receiver that already has them can ignore the copies.
Pull the audit log instead
An Owner or Admin can page through the log with a session or a personal token with the admin:read scope (only an Owner or Admin can give a token that scope):
curl -H "Authorization: Bearer $MISSIVED_TOKEN" \
"https://api.missived.com/v1/orgs/<orgId>/audit-events?limit=500&since=2026-10-01T00:00:00Z"
- Newest first. Up to 1,000 a page (default 100); pass the answer's
next_cursorascursorfor the next page, untilhas_moreis false. - Filters:
since,until,action(an exact name) andactor_id. - Each item has the Simple JSON fields above plus
ocsf, the OCSF envelope.
See listAuditEvents. App tokens can't read the audit log.
Destinations themselves are managed only from the Integrations page, signed in; API tokens can't manage them yet.
What data moves
- Missived sends your receiver each matching audit event: the action, when, the outcome, the actor's id and label (often their email address), the target's type, id and label, and the event's details (metadata). Never message content.
- Sign-ins, sign-outs and account registrations are account-wide, not part of any one org, so they are not in an org's audit stream.
- Missived stores the destination's URL and its signing secret, Ed25519 key and extra header value, encrypted, plus a delivery log of statuses and response snippets.
- Adding, changing, rotating, pausing, resuming and deleting a destination are themselves audit events.
Limits
- Destinations per org: Free 1, Ministry 2, Creator 2, Business 10. At the limit, adding one is refused ("Destination limit reached for this plan").
- 10 seconds to answer each delivery; 24 hours of retries per delivery.
- Up to 100 action patterns per destination.
Troubleshooting
- "url must point to a public address" or "must be an https:// URL": the receiver must be public https.
- Every delivery fails signature checks: verify the raw bytes before any JSON parsing, and check the secret wasn't rotated without updating the receiver.
- Paused after 20 consecutive failures: fix the receiver, then Resume, then Replay 24h for what it missed.
- Switched off, "the receiver answered 410 Gone": your receiver asked for it. Resume if that was a mistake.
- Some events never arrive: check Which events and Only these actions; a filter that's too narrow drops them.