Journal export
Download the signed journal as JSON Lines, or receive chosen events as they happen.
On this page
Every call, decision and change lands in your journal. Take a full copy whenever you like, for your SIEM or your archive.
Download it from the console
Open Activity and press Download journal. The file holds the whole chain your organization has. Owners can download it, and so can admins and auditors of the whole organization who hold no narrower role in any workspace. An admin or auditor of one workspace cannot. Neither can an organization admin who is only a member or a guest of one client’s workspace. To read it on screen, open the Journal tab beside it: every entry, who made it and what it is about. Each person sees the entries of the workspaces where they are an owner, admin or auditor, and the organization’s own.
Download it from a script
A script signs in with a console API key. An owner creates one in API keys with New API key, and it is shown once. Keep it in SALLYPORT_CONSOLE_KEY:
read -rs SALLYPORT_CONSOLE_KEY && export SALLYPORT_CONSOLE_KEYcurl --fail --silent --show-error -H "Authorization: Bearer $SALLYPORT_CONSOLE_KEY" "https://mcp.sallyport.cloud/v1/audit/export" -o sallyport-audit.jsonlAdd from_seq and to_seq to take a range. Both are whole numbers from zero, and both ends are included. Without to_seq the file runs to the end of the chain.
curl --fail --silent --show-error -H "Authorization: Bearer $SALLYPORT_CONSOLE_KEY" "https://mcp.sallyport.cloud/v1/audit/export?from_seq=1001" -o sallyport-audit-1001.jsonlTo pull only what is new, read to_seq from the first line of the last file and start the next pull one entry later. If events is 0, nothing is new: pull again later with the same from_seq.
Sallyport keeps 180 days of journal by default, so pull at least that often. Journal and call history (days) in Settings, Organization, changes it. The console session uses the same route at https://my.sallyport.cloud/api/v1/audit/export.
What the file holds
| Response header | Value |
|---|---|
| Content-Type | application/x-ndjson; charset=utf-8 |
| Content-Disposition | attachment; filename="sallyport-audit-{tenant UUID}.jsonl" |
| Cache-Control | no-store |
| X-Content-Type-Options | nosniff |
The first line names the file: schema (spc-chain/2), tenant_id, from_seq, to_seq and events. Every next line is one entry in order: seq, occurred_at, kind, payload, prev_hash, this_hash, sig and signer_kid.
Each entry carries the hash of the one before it, so a missing or edited line breaks the chain. Each entry is signed with Ed25519, and the public keys are at https://mcp.sallyport.cloud/.well-known/sallyport-audit-keys.json with no account needed.
Count the lines against events to catch a download that stopped early. The file carries no key values, no request bodies and no full argument lists.
Receive events as they happen
A webhook posts each new journal entry of the kinds you pick to your HTTPS endpoint, within about a minute. An owner or admin adds one in Webhooks, Settings: press Add webhook, enter the endpoint and tick the events. A script uses the API:
curl --fail --silent --show-error -X POST -H "Authorization: Bearer $SALLYPORT_CONSOLE_KEY" -H "Content-Type: application/json" -d '{"url": "https://siem.example.com/sallyport", "events": ["call.intent", "call.result", "approval.decided"]}' "https://mcp.sallyport.cloud/v1/webhooks"The signing secret is shown once: in the console after Add webhook, and as secret in the API answer. Each delivery is a POST with X-Sallyport-Event, X-Sallyport-Delivery and X-Sallyport-Signature: t=<unix seconds>,v1=<hex>.
Check v1 as HMAC-SHA256 of <t>.<body>, keyed with the whole secret. The body holds delivery_id, tenant_id, kind, occurred_at, seq, this_hash and payload.
- Answer with a 2xx status. A failed delivery is tried again with doubling pauses from 5 seconds, 8 attempts in all. After about 15 minutes it is marked failed.
- Retries keep the same
X-Sallyport-Delivery, so drop repeats by it. - A webhook delivers what its creator may read of the journal. That is the entries of workspaces where they are an owner, admin or auditor, plus the organization’s own. While they may read none of it, the webhook delivers nothing, and those entries are not sent later. A webhook created with an API key delivers the whole journal.
- A webhook starts at the moment it is created. For older entries, use the export;
seqandthis_hashmatch its lines. - Event names are the journal’s
kindvalues, such ascall.intent,call.result,approval.requested,approval.decided,grant.createdandaccess_request.created. Anykindyou find in the export works. An unknown name is refused when you create the webhook, and the error quotes it. - Deliveries on the webhook’s row lists what was sent, and Send again resends a failed one. The API has
GET /v1/webhooks/{id}/deliveriesandPOST /v1/webhooks/{id}/deliveries/{delivery_id}/retry. - The list in Webhooks marks a webhook that is failing. Its switch turns deliveries off without deleting it.