Generic HTTPS (JSON)
Works with: anything that takes JSON over HTTPS: Sumo Logic (HTTP source), Cribl, Logstash
(http input), Graylog (HTTP input), the Elastic Agent HTTP endpoint input, or your own receiver.
What SafeHanded sends
Section titled “What SafeHanded sends”A POST with Content-Type: application/json, up to 500 events per request, in order:
{ "source": "safehanded", "version": 1, "org_id": "01h…", "events": [ { "seq": 41, "prev_hash": "…", "hash": "…", "sig": "…", "sig_key_id": "…", "event": "revealed", "level": "security", "actor_type": "member", "actor_id": "…", "actor_label": "Jane Smith <jane@example.com>", "request_id": "…", "share_id": null, "client_id": null, "ip": "203.0.113.9", "user_agent": "…", "metadata": {}, "created_at": "2026-10-01T12:00:00Z" } ]}With OCSF chosen, each item in events is an OCSF 1.1 event instead.
Answer with any 2xx to accept the batch. A timeout, 408, 429 or 5xx is retried up to three times
in the same run (honouring Retry-After up to 10 seconds). If the batch still isn’t accepted, the
destination is marked Needs attention and later runs try again from the same event, backing off from
one minute up to fifteen while it keeps failing, until it is accepted.
Authentication
Section titled “Authentication”Choose one:
- Bearer token:
Authorization: Bearer <token>. - HMAC signature:
X-SafeHanded-Signature: t=<unix seconds>,v1=<hex>, wherev1is HMAC-SHA256 with your secret over"<t>.<raw body>". Recompute it over the exact bytes received, compare in constant time, and reject atmore than five minutes old.
[$t, $v1] = sscanf($header, 't=%d,v1=%s');$ok = abs(time() - $t) <= 300 && hash_equals(hash_hmac('sha256', $t.'.'.$rawBody, $secret), $v1);Connect
Section titled “Connect”Settings → Integrations → Connect → Generic HTTPS (JSON): endpoint URL, authentication,
token or secret (8 characters or more) and format. Save, then Send test event. The test event has
"event": "siem_test" and "seq": 0.
De-duplicate on org_id + seq: after a failure an event can be delivered twice.