Overview
SparkVault records security-relevant activity in a unified audit log. Every entry captures what happened (event_type), when (timestamp), who did it (actor_id), and from where (ip_address, user_agent), plus event-specific metadata. Events are partitioned into four scopes, each with its own list endpoint:
| Scope | What it records | Endpoint | Auth |
|---|---|---|---|
| Account | Logins, user and license management, billing, API keys, custom domains, vault create/delete, SparkLink receipts, Messaging governance | GET /v1/audit-logs |
API key or JWT |
| Integration / Product | Per-integration and per-product event streams (Slack, HubSpot, Identity, Structured Ingots, …), called apps in the API |
GET /v1/audit-logs/apps/{app_slug} |
API key or JWT |
| Vault | Vault settings, seal/unseal, sharing, upload portals, DVAKs, folder operations | GET /v1/vaults/{vault_id}/audit-logs |
API key or JWT + X-Vault-Access-Token |
| Ingot | Per-file activity: uploads, downloads, accesses, renames, sharing | GET /v1/vaults/{vault_id}/ingots/{ingot_id}/audit-logs |
API key or JWT + X-Vault-Access-Token |
Entries are returned newest-first with signed cursor pagination. Account and integration entries are stored in plaintext. Vault and ingot entry metadata is encrypted at rest with AES-256-GCM under a key derived (HKDF) from the vault's Vault Access Key (VAK) when the event is recorded through an unsealed session. It can only be decrypted with a valid Vault Access Token. Events recorded outside a vault session (such as retention_changed) store their metadata in plaintext.
Entry Fields
Audit Log Entry
| Field | Type | Description |
|---|---|---|
timestamp |
integer | Unix timestamp of the event in epoch seconds |
event_type |
string | Event identifier (see Event Types) |
actor_id |
string? | Who performed the action: a user (usr_...) or an API key (key_...). null for unattributed events; omitted on integration-scope entries. |
actor_type |
string? | user or api_key, present when the actor still exists in your account and could be resolved |
actor_display |
string? | Human-readable actor: the user's email or the API key's name, present when resolved |
ip_address |
string? | Client IP address that triggered the event |
user_agent |
string? | Client user agent |
metadata |
object? | Event-specific details. Decrypted transparently on vault/ingot endpoints using your VAT session; null when the event carries none. |
vault_id |
string? | Present on vault- and ingot-scope entries |
ingot_id |
string? | Present on ingot-scope entries |
app_slug |
string? | Present on integration-scope entries |
Audit logs answer who did what, and when. For usage aggregates and analytics dashboards, see Reporting.
Event Types
Each scope has its own set of event types. The account, vault, and ingot list endpoints return the full valid set for their scope in the response's event_types field, so you can build filters without hardcoding the lists below.
Account Events
| Category | Event Types |
|---|---|
| User management | user_invited, user_removed, user_role_changed |
| License management | user_seat_type_set, user_license_cancel_scheduled, user_license_cancel_undone, user_license_released, license_migration_applied |
| Authentication | login, logout, login_failed |
| Identity verification | auth_attempt, auth_success, auth_failure |
| Account settings | email_changed, name_changed, organization_name_changed, logo_updated |
| Custom domains | custom_domain_added, custom_domain_removed, custom_domain_verified |
| Vault lifecycle | vault_created, vault_deleted |
| Billing | payment_added, payment_failed, credit_card_added, credit_card_removed |
| API keys | api_key_created, api_key_revoked |
| SparkLink lifecycle | sparklink_created, sparklink_deleted, sparklink_revoked |
| Verified-interaction receipts | sparklink_accessed, sparklink_signed, sparklink_approved, sparklink_denied, sparklink_replied |
| Messaging governance | messaging_conversation_created, messaging_participant_added, messaging_participant_removed, messaging_recipient_verified, messaging_message_sent, messaging_message_recalled, messaging_opted_out, messaging_opted_in, messaging_legal_hold_set, messaging_legal_hold_cleared, messaging_receipt_issued |
The account-scope event_types response set also includes platform-admin event types (admin_impersonate, admin_account_deleted, admin_status_changed, admin_pricing_updated, admin_blocklist_source_toggled, admin_blocklist_domain_added, admin_blocklist_domain_removed). These are recorded only under the SparkVault platform admin account, so your own audit logs will never contain them.
Verified-interaction receipt events (sparklink_accessed, sparklink_signed, sparklink_approved, sparklink_denied, sparklink_replied) are recorded at the account scope in plaintext so they can be presented as third-party proof without a vault key: the signed EdDSA receipt token and action_hash ride in metadata and are JWKS-verifiable. Messaging events never contain message content: only IDs, the verified sender, and the SparkVault-signed receipt token.
Vault Events
| Category | Event Types |
|---|---|
| Vault operations | vault_renamed, vault_settings_changed, vault_unsealed, vault_sealed |
| Sharing | sharing_enabled, sharing_disabled, sharing_config_changed |
| Upload portal and widget | upload_portal_enabled, upload_portal_disabled, upload_portal_repaired, upload_widget_enabled, upload_widget_disabled, upload_widget_repaired |
| VMK hosting | vmk_hosted, vmk_removed, hvmk_key_created |
| Delegated Vault Access Keys | dvak_created, dvak_revoked, dvak_used, dvak_auto_revoked |
| Folders | folder_created, folder_renamed, folder_moved, folder_deleted, folder_updated |
| Retention | retention_changed |
Ingot Events
| Category | Event Types |
|---|---|
| Lifecycle | ingot_created, ingot_renamed, ingot_deleted, ingot_moved |
| Sharing | ingot_shared, ingot_unshared, invite_created, invite_revoked |
| Access | ingot_accessed, ingot_downloaded, ingot_uploaded |
| SparkLink access | sparklink_accessed |
| Errors | upload_error, download_error |
Integration and Product Events
Integration-scope event types are free-form strings: integrations and products define their own. Common patterns:
| Category | Event Types |
|---|---|
| Installation | app_installed, app_uninstalled, app_config_changed |
| Identity Product | passkey_created, passkey_removed |
| Slack Integration | slack_connected, slack_disconnected, slack_message_sent |
| Structured Ingots Product | structure_created, structure_updated, key_accessed |
Pagination and Filtering
All list endpoints share the same cursor-based pagination and filtering contract:
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
integer | Optional | Maximum entries per page. Values outside 1-100 are clamped into range.Default: 25 |
cursor |
string | Optional | Opaque signed pagination cursor: pass back the next_cursor from the previous responseDefault: null |
event_types |
string | Optional | Comma-separated event type filter, e.g. ?event_types=login,login_failedDefault: none (all events) |
- Ordering: entries are returned newest-first;
timestampis epoch seconds. has_more/next_cursor:next_cursoris present only whenhas_moreistrue. Keep requesting with?cursor=untilhas_moreisfalse.- Signed cursors: cursors are HMAC-signed per account and bound to the exact audit scope they were minted for. A tampered cursor, a cursor from another account, or a cursor replayed against a different scope returns
400 VALIDATION_ERROR. - Filtered pages can run short: with an
event_typesfilter, a page may contain fewer thanlimitentries (even zero) whilehas_moreis stilltrue. Always page byhas_more, not by page size.
Account Audit Logs
/v1/audit-logs
List account-scope audit logs: authentication, user and license management, billing, API keys, custom domains, vault lifecycle, SparkLink receipts, and Messaging governance events.
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
integer | Optional | Maximum entries per page (1-100)Default: 25 |
cursor |
string | Optional | Signed pagination cursor from a previous responseDefault: null |
event_types |
string | Optional | Comma-separated filter of account event typesDefault: none (all events) |
Response
| Field | Type | Description |
|---|---|---|
entries |
array | Audit log entries, newest first (see Entry Fields in the Overview) |
count |
integer | Number of entries in this page |
has_more |
boolean | Whether more pages exist |
next_cursor |
string? | Signed cursor for the next page (present when has_more is true) |
event_types |
string[] | Every valid account-scope event type, useful for building filter UIs |
List Recent Logins
Requestcurl "https://api.sparkvault.com/v1/audit-logs?limit=2&event_types=login,login_failed" \
-H "X-API-Key: sv_live_xxx"
{
"data": {
"entries": [
{
"timestamp": 1702000600,
"event_type": "login",
"actor_id": "usr_abc123...",
"actor_type": "user",
"actor_display": "admin@example.com",
"ip_address": "203.0.113.7",
"user_agent": "Mozilla/5.0...",
"metadata": null
},
{
"timestamp": 1702000000,
"event_type": "login_failed",
"actor_id": null,
"ip_address": "198.51.100.23",
"user_agent": "Mozilla/5.0...",
"metadata": null
}
],
"count": 2,
"has_more": true,
"next_cursor": "eyJrZXkiOnsi...",
"event_types": ["user_invited", "user_removed", "user_role_changed", "..."]
}
}
Integration and Product Audit Logs
Every installed integration and every product keeps its own event stream, addressed by its slug. The API calls this scope apps. Integration-scope entries record timestamp, event_type, metadata, and app_slug. They carry no actor or IP fields.
/v1/audit-logs/apps/{app_slug}
List the audit log for one integration or product stream.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
app_slug |
string | Required | Slug of the integration or product stream, e.g. slack |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
integer | Optional | Maximum entries per page (1-100)Default: 25 |
cursor |
string | Optional | Signed pagination cursor from a previous responseDefault: null |
event_types |
string | Optional | Comma-separated event type filterDefault: none (all events) |
Response
| Field | Type | Description |
|---|---|---|
entries |
array | Audit log entries, newest first |
count |
integer | Number of entries in this page |
has_more |
boolean | Whether more pages exist |
next_cursor |
string? | Signed cursor for the next page (present when has_more is true) |
app_slug |
string | The requested stream slug |
List Slack Integration Events
Requestcurl "https://api.sparkvault.com/v1/audit-logs/apps/slack?limit=25" \
-H "X-API-Key: sv_live_xxx"
{
"data": {
"entries": [
{
"timestamp": 1702000000,
"event_type": "slack_connected",
"metadata": null,
"app_slug": "slack"
}
],
"count": 1,
"has_more": false,
"app_slug": "slack"
}
}
/v1/audit-logs/apps
Append an event to an integration or product stream. Event types are free-form, so your own automations can write their own audit trail. Returns 201 Created.
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
app_slug |
string | Required | Stream to log under, e.g. slack |
event_type |
string | Required | Free-form event identifier |
metadata |
object | Optional | Arbitrary event details stored with the entry (plaintext; never put secrets here)Default: null |
Response
| Field | Type | Description |
|---|---|---|
logged |
boolean | true: the entry was written |
app_slug |
string | Stream the entry was written to |
event_type |
string | The recorded event type |
Log a Custom Event
Requestcurl -X POST https://api.sparkvault.com/v1/audit-logs/apps \
-H "X-API-Key: sv_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"app_slug": "hubspot",
"event_type": "export_completed",
"metadata": { "record_count": 42 }
}'
{
"data": {
"logged": true,
"app_slug": "hubspot",
"event_type": "export_completed"
}
}
Audit streams are append-only: entries cannot be edited or deleted through the API, and each POST writes a new entry. SparkVault's own integrations and products log to these streams via internal service calls.
Vault Audit Logs
/v1/vaults/{vault_id}/audit-logs
List vault-scope audit logs: settings, seal/unseal, sharing, upload portals, DVAKs, and folder operations. Requires an unsealed vault session (VAT).
This endpoint requires the X-Vault-Access-Token header with a valid VAT obtained by unsealing the vault. Entry metadata is stored encrypted and is decrypted transparently with the VAK held by your VAT session. Vault-scope events cover the vault itself. Per-file events live on the per-ingot endpoint.
Path Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
vault_id |
string | Required | Vault identifier (vlt_...) |
Query Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
limit |
integer | Optional | Maximum entries per page (1-100)Default: 25 |
cursor |
string | Optional | Signed pagination cursor from a previous responseDefault: null |
event_types |
string | Optional | Comma-separated filter of vault event typesDefault: none (all events) |
Response
| Field | Type | Description |
|---|---|---|
entries |
array | Audit log entries, newest first; each includes vault_id |
count |
integer | Number of entries in this page |
has_more |
boolean | Whether more pages exist |
next_cursor |
string? | Signed cursor for the next page (present when has_more is true) |
vault_id |
string | The requested vault |
event_types |
string[] | Every valid vault-scope event type |
List Vault Events
Requestcurl "https://api.sparkvault.com/v1/vaults/vlt_abc123/audit-logs?limit=25" \
-H "X-API-Key: sv_live_xxx" \
-H "X-Vault-Access-Token: vat_xyz789..."
{
"data": {
"entries": [
{
"timestamp": 1702000000,
"event_type": "vault_unsealed",
"actor_id": "usr_abc123...",
"actor_type": "user",
"actor_display": "admin@example.com",
"ip_address": "203.0.113.7",
"user_agent": "Mozilla/5.0...",
"metadata": { "ttl_seconds": 3600 },
"vault_id": "vlt_abc123..."
}
],
"count": 1,
"has_more": false,
"vault_id": "vlt_abc123...",
"event_types": ["vault_renamed", "vault_settings_changed", "..."]
}
}
The VAT must belong to the requested vault and to your account: a mismatch, or a token that has expired, returns 403 FORBIDDEN. A missing, malformed, or unknown token returns 401 AUTHENTICATION_ERROR, and a vault that does not exist (or is not owned by your account) returns 404 NOT_FOUND.
Ingot Audit Logs
/v1/vaults/{vault_id}/ingots/{ingot_id}/audit-logs
List per-ingot audit logs: uploads, downloads, accesses, renames, moves, and sharing on a single file. Requires an unsealed vault session (VAT).
The per-ingot endpoint follows the same auth, pagination, and filtering contract as the vault endpoint above: X-Vault-Access-Token required, encrypted metadata decrypted via your VAT session, and a response carrying entries (each with vault_id and ingot_id), count, has_more, next_cursor, and the valid ingot-scope event_types. Full documentation lives on the Ingots page.
Retention
Every audit entry is written with an expiry and is removed automatically when it lapses. The default retention window is 90 days (7,776,000 seconds).
Each vault additionally carries a configurable access-log retention setting (GET/PUT /v1/vaults/{vault_id}/access-log-retention, see the Vaults docs) that governs how long ingot access events recorded through public sharing surfaces (public portal uploads and SparkLink downloads) are kept. Setting it to 0 (Disabled) turns that logging off entirely: no entries are written. The change itself is always recorded as a retention_changed vault event under the default window, so the configuration trail survives even when access logging is disabled.
| Value (seconds) | Window |
|---|---|
0 | Disabled: no access-log entries are written |
86400 | 24 hours |
604800 | 7 days |
2592000 | 1 month |
5184000 | 2 months |
7776000 | 3 months (default) |
15552000 | 6 months |
23328000 | 9 months |
31536000 | 1 year |
63072000 | 2 years |
94608000 | 3 years |
Audit logs are owned by the entity they describe. Deleting an ingot, a vault, an integration installation, or your account permanently deletes the audit history recorded under it. Export anything you need for compliance before deleting.
Error Reference
Error Responses
| Status | Code | Description |
|---|---|---|
| 400 | VALIDATION_ERROR |
Invalid or tampered pagination cursor (wrong account or scope), or missing app_slug/event_type when creating an entry |
| 401 | AUTHENTICATION_ERROR |
Missing or invalid API key/JWT; missing, malformed, or unknown X-Vault-Access-Token on vault and ingot endpoints |
| 403 | FORBIDDEN |
The VAT belongs to a different vault or account than the one requested, or the token has expired |
| 404 | NOT_FOUND |
Vault does not exist or is not owned by your account |
| 429 | RATE_LIMIT_EXCEEDED |
Too many requests |