Events
Query the immutable audit trail of all system activities
Events
Events are the immutable audit trail of everything that happens in VirtuousAI. Every action, connection change, and automation run generates events that you can query, filter, and subscribe to.
Concept
Each event contains:
- Type — What happened (e.g.,
action.completed) - Entity — What was affected (e.g.,
action_xyz) - Actor — Who/what caused it (e.g.,
user_abc,system) - Data — Event-specific payload (e.g.,
{ records: 1250 }) - Timestamp — When it happened (UTC)
Events are:
- Immutable — Cannot be modified after creation
- Append-only — New events always added, never removed
- Correlated — Related events share a correlation ID
Event Structure
{
"id": "evt_abc123",
"type": "action.completed",
"timestamp": "2026-01-22T14:32:15Z",
"entity": {
"type": "action_run",
"id": "run_xyz789"
},
"actor": {
"type": "automation",
"id": "auto_abc123"
},
"data": {
"duration": 135000,
"recordsProcessed": 1250,
"status": "COMPLETED"
},
"metadata": {
"correlationId": "corr_abc123",
"organizationId": "org_xyz"
}
}Event Types
| Type | Description | Typical Actor |
|---|---|---|
connection.created | New connection created | user |
connection.updated | Settings modified | user |
connection.deleted | Connection removed | user |
connection.tested | Connectivity test run | user, system |
connection.error | Error occurred | system |
connection.token_refreshed | OAuth token refreshed | system |
| Type | Description | Typical Actor |
|---|---|---|
action.created | New action created | user |
action.started | Execution started | user, automation |
action.progress | Execution progress update | system |
action.completed | Finished successfully | system |
action.failed | Finished with error | system |
action.cancelled | Manually cancelled | user |
| Type | Description | Typical Actor |
|---|---|---|
automation.created | New automation created | user |
automation.triggered | Trigger fired | system, api |
automation.completed | Run finished successfully | system |
automation.failed | Run finished with error | system |
automation.enabled | Automation enabled | user |
automation.disabled | Automation disabled | user |
| Type | Description | Typical Actor |
|---|---|---|
auth.login | User logged in | user |
auth.logout | User logged out | user |
auth.token_created | API token created | user |
auth.token_revoked | API token revoked | user |
auth.permission_granted | Permission added | user |
auth.permission_revoked | Permission removed | user |
Actor Types
| Actor Type | Description | Includes |
|---|---|---|
user | Human via UI or CLI | email, IP, user agent |
system | Internal processes | process name, version |
automation | Triggered by automation | automation ID |
api | External API call | API key ID, IP |
Querying Events
Filtering
GET /api/v1/events?type=action.completed&since=2026-01-20T00:00:00Z| Parameter | Description |
|---|---|
type | Filter by event type (e.g., action.completed) |
entityType | Filter by entity type (e.g., action) |
entityId | Filter by specific entity ID |
since | Events after this timestamp |
until | Events before this timestamp |
actorType | Filter by actor type (user, system, etc.) |
actorId | Filter by specific actor |
correlationId | Get all events in a correlation chain |
Pagination
Events use cursor-based pagination:
{
"items": [...],
"nextCursor": "eyJ0cyI6IjIwMjYtMDEtMjBUMTQ6MzI6MTVaIn0=",
"hasMore": true
}Cursor Expiration
Cursors are valid for 24 hours. For long-running exports, use the since/until parameters instead.
Webhooks
Subscribe to events in real-time via webhooks:
Creating a Webhook Subscription
POST /api/v1/webhooks
{
"url": "https://your-server.com/webhook",
"events": ["action.completed", "action.failed"],
"secret": "whsec_your_secret"
}Verifying Signatures
All webhook payloads include a signature header:
X-VAI-Signature: sha256=abc123def456...
X-VAI-Timestamp: 1705764735Verify by computing HMAC-SHA256 of {timestamp}.{payload} with your secret:
const crypto = require('crypto');
function verifyWebhook(payload, signature, timestamp, secret) {
const signedPayload = `${timestamp}.${payload}`;
const expectedSignature = crypto
.createHmac('sha256', secret)
.update(signedPayload)
.digest('hex');
return `sha256=${expectedSignature}` === signature;
}Use Cases
Audit & Compliance
Query all actions by a specific user:
GET /api/v1/events?actorType=user&actorId=user_abc123&since=2026-01-01Debugging Failures
Find all events for a failed action:
GET /api/v1/events?entityId=run_xyz789&type=action.*Correlation Tracing
Get all events in a workflow:
GET /api/v1/events?correlationId=corr_abc123Building Dashboards
Stream events to build real-time monitoring:
{
"url": "https://dashboard.internal/events",
"events": [
"action.completed",
"action.failed",
"automation.triggered",
"connection.error"
]
}Best Practices
- Use correlation IDs — When debugging, find one event and query others with the same correlation ID
- Subscribe selectively — Only subscribe to events you need to reduce webhook load
- Verify signatures — Always verify webhook signatures in production
- Handle retries idempotently — Webhooks may be delivered more than once
- Set up alerting — Create webhooks for error events to trigger alerts
- Archive for compliance — Export events periodically for long-term retention
OpenAPI Reference
For detailed endpoint schemas, request/response formats, and authentication: