First Seal

Seal a Fact in 5 Minutes

Audience: CTO · Staff Engineer · SRE

One Endpoint

POST /v2/streams/{stream_id}/facts
Content-Type: application/json

A stream is identified by stream_id, provided by the client in the URL. If no stream with that ID exists, Horizon creates it implicitly when the first fact is sealed.

One Request

{
  "tenant_id": "acme-corp",
  "actor": "ops-lead@acme-corp.com",
  "custom_payload": {
    "action": "stop_service",
    "context": "Memory leak confirmed"
  }
}

In production deployments, tenant_id is typically derived from authentication context rather than provided in the payload.

One Response

{
  "fact_id": "fact-01HRX7G2NB",
  "stream_id": "stream-034",
  "tenant_id": "acme-corp",
  "actor": "ops-lead@acme-corp.com",
  "sealed_at_ms": 1706284801000,
  "custom_payload": {
    "action": "stop_service",
    "context": "Memory leak confirmed"
  },
  "fact_hash": "a1b2c3d4e5f6...",
  "prev_hash": "9f8e7d6c5b4a...",
  "parent_fact_id": "fact-01HRX7F1MA"
}

What Happened

  1. Horizon assigned sealed_at_ms (authoritative timestamp)
  2. Horizon computed fact_hash from a deterministic representation of the fact
  3. Horizon chained to previous fact via prev_hash
  4. Horizon stored the fact (append-only)

Horizon did not interpret custom_payload. That's your data.


Idempotency

Add client_ref to make the request idempotent:

{
  "tenant_id": "acme-corp",
  "actor": "ops-lead@acme-corp.com",
  "client_ref": "incident-2024-01-26-stop-001",
  "custom_payload": { ... }
}

Same client_ref → same fact returned. No duplicate sealing.


Storage Guarantees

PropertyGuarantee
Append-onlyFacts cannot be modified or deleted
Hash chainEach fact links to previous via prev_hash
Tamper detectionRecompute hashes to detect modification
Tenant isolationFacts scoped by tenant_id
Proof authoritysealed_at_ms assigned by Horizon

What Horizon Does Not Do

  • No interpretation- custom_payload is opaque
  • No workflow- No states, no transitions, no approvals
  • No validation- Your payload, your schema
  • No business logic- Seal facts, nothing else

Verify Chain Integrity

POST /v2/streams/{stream_id}/verify

Returns { "valid": true } if hash chain is intact.

Verification recomputes hashes and signatures. It does not interpret facts or assert correctness.