Skip to main content
Every alert in Calseta is normalized to an agent-native schema — clean field names designed for AI consumption. Regardless of which source system sent the alert, agents always see the same structure.

Alert Fields

FieldTypeDescription
uuidstring (UUID)Unique identifier for the alert
titlestringAlert title (from the source system)
severitystringPending, Informational, Low, Medium, High, Critical
source_namestringWhich source sent the alert (sentinel, elastic, splunk, generic)
statusstringInvestigation lifecycle state (see below)
enrichment_statusstringSystem-managed enrichment state (see below)
occurred_attimestampWhen the event occurred (from the source system)
tagsstring[]User-defined and source-derived tags
raw_payloadobjectOriginal source payload, preserved in full
acknowledged_attimestampSet on first transition out of Open
triaged_attimestampSet when entering Triaging
closed_attimestampSet when entering Closed
close_classificationstringClassification when closing (e.g., True Positive, False Positive)
created_attimestampWhen Calseta received the alert
updated_attimestampLast modification time

Alert Status

The status field tracks the investigation lifecycle. Transitions are enforced by the API:
Open ──▶ Triaging ──▶ Closed
  │                     ▲
  ├──▶ Escalated ───────┘

  └──▶ Closed
StatusDescription
OpenNew alert, not yet acknowledged
TriagingUnder active investigation
EscalatedEscalated to a human or team
ClosedInvestigation complete

Lifecycle Timestamps

These are set automatically by Calseta — they cannot be set via the API:
  • acknowledged_at — set on the first transition out of Open (to Triaging, Escalated, or Closed)
  • triaged_at — set when entering Triaging
  • closed_at — set when entering Closed

Enrichment Status

The enrichment_status field is system-managed and tracks the enrichment pipeline progress. It is separate from status and cannot be set via the API.
Enrichment StatusDescription
PendingEnrichment has not completed yet
EnrichedAll providers have returned results
FailedOne or more providers failed

Severity Levels

SeverityDescription
PendingSeverity not yet determined
InformationalNo action needed, for awareness only
LowMinor risk, investigate when time permits
MediumModerate risk, investigate within SLA
HighSignificant risk, investigate promptly
CriticalSevere risk, immediate investigation required
Source systems map their own severity values to these. Unknown or missing severity defaults to Pending. Each alert links to additional data available via sub-endpoints:
DataEndpointDescription
IndicatorsGET /v1/alerts/{uuid}/indicatorsExtracted IOCs with enrichment results and malice verdicts
ContextGET /v1/alerts/{uuid}/contextMatched context documents (runbooks, SOPs, IR plans)
FindingsGET /v1/alerts/{uuid}/findingsAgent analysis output posted back to the alert
ActivityGET /v1/alerts/{uuid}/activityImmutable audit log of every action on the alert

The _metadata Block

The GET /v1/alerts/{uuid} and webhook payload responses include a computed _metadata block:
{
  "_metadata": {
    "generated_at": "2025-01-15T10:35:00Z",
    "alert_source": "sentinel",
    "indicator_count": 3,
    "enrichment": {
      "succeeded": ["virustotal", "abuseipdb"],
      "failed": [],
      "enriched_at": "2025-01-15T10:30:05Z"
    },
    "detection_rule_matched": true,
    "context_documents_applied": 2
  }
}
This block is computed at serialization time — no additional database columns.

Why Not OCSF?

Calseta uses its own schema instead of the Open Cybersecurity Schema Framework (OCSF). OCSF is designed for data producers (EDR, network, identity vendors) mapping fields so SIEMs can ingest from diverse sources. It uses numeric class IDs, epoch timestamps, and unmapped buckets optimized for SIEM indexing. AI agents need different things: readable field names, structured enrichment data as a first-class concept, and a relational indicator model. Calseta’s schema is designed from the ground up for agent consumption. Source-specific fields that don’t map to the Calseta schema are preserved in raw_payload, so no data is lost.