API Reference
Base URL: https://api.horizon.example.com
All requests use JSON. All timestamps are in milliseconds (Unix epoch) with ISO 8601 representation.
Authentication
Include your API key in the X-API-Key header:
X-API-Key: your-api-key-hereEndpoints Overview
| Endpoint | Method | Description |
|---|---|---|
| /streams/{stream_id}/facts | POST | Seal a new fact |
| /streams/{stream_id}/facts | GET | List facts in a stream |
| /streams/{stream_id}/bundles | POST | Create proof bundle |
| /streams/{stream_id}/bundles | GET | List bundles for a stream |
| /streams/{stream_id}/verify | POST | Verify chain integrity |
| /facts/{fact_id} | GET | Get a single fact |
| /bundles/{bundle_id} | GET | Get a single bundle |
| /tenants/{tenant_id}/streams | GET | List streams for a tenant |
| /health | GET | Health check |
Seal a Fact
Creates a new fact in a stream. If the stream doesn't exist, it is created automatically.
POST /streams/{stream_id}/factsRequest Body
| Field | Type | Required | Description |
|---|---|---|---|
| tenant_id | string | Yes | Your tenant identifier |
| actor | string | Yes | Who is making this declaration |
| custom_payload | object | Yes | Your business data (opaque to Horizon) |
| client_ref | string | No | Idempotency key (prevents duplicates) |
Example Request
{
"tenant_id": "acme-corp",
"actor": "ops-lead@acme-corp.com",
"custom_payload": {
"decision": "Approve emergency maintenance",
"justification": "Memory leak confirmed",
"affected_systems": ["api-server-01", "api-server-02"]
},
"client_ref": "incident-2024-01-26-approval-001"
}Example Response
{
"fact_id": "fact-01HRX7G2NB",
"stream_id": "incident-2024-01-26",
"tenant_id": "acme-corp",
"actor": "ops-lead@acme-corp.com",
"sealed_at_ms": 1706284801000,
"sealed_at_iso": "2024-01-26T12:00:01.000Z",
"custom_payload": {
"decision": "Approve emergency maintenance",
"justification": "Memory leak confirmed",
"affected_systems": ["api-server-01", "api-server-02"]
},
"fact_hash": "a1b2c3d4e5f6...",
"prev_hash": "9f8e7d6c5b4a...",
"parent_fact_id": "fact-01HRX7F1MA"
}Idempotency
If you provide client_ref, Horizon ensures exactly-once sealing. First request: fact is created. Subsequent requests with same client_ref: original fact is returned. This is safe for retries in unreliable network conditions.
List Facts (Timeline)
Returns all facts in a stream, in chain order.
GET /streams/{stream_id}/facts?limit=100&offset=0{
"facts": [
{
"fact_id": "fact-01HRX7F1MA",
"sealed_at_ms": 1706284800000,
"sealed_at_iso": "2024-01-26T12:00:00.000Z",
"actor": "system:monitoring",
"custom_payload": { "alert": "Memory usage at 95%" }
},
{
"fact_id": "fact-01HRX7G2NB",
"sealed_at_ms": 1706284801000,
"sealed_at_iso": "2024-01-26T12:00:01.000Z",
"actor": "ops-lead@acme-corp.com",
"custom_payload": { "decision": "Approve emergency maintenance" }
}
],
"count": 2
}Create Proof Bundle
Creates a signed, exportable snapshot of the stream.
POST /streams/{stream_id}/bundles{
"bundle_id": "bundle-01HRX8ABC",
"stream_id": "incident-2024-01-26",
"bundle_version": 1,
"head_fact_id": "fact-01HRX7G2NB",
"head_hash": "a1b2c3d4e5f6...",
"facts_manifest": ["fact-01HRX7F1MA", "fact-01HRX7G2NB"],
"created_at_ms": 1706284900000,
"created_at_iso": "2024-01-26T12:01:40.000Z",
"signature": "base64-encoded-signature...",
"signature_alg": "ed25519",
"key_id": "horizon-key-001"
}Verify Chain Integrity
Verifies that the hash chain is intact.
POST /streams/{stream_id}/verifyValid Response
{
"valid": true,
"facts_verified": 47
}Tampered Response
{
"valid": false,
"facts_verified": 23,
"error": "Hash chain broken at fact-01HRX8XYZ"
}Error Codes
| Code | HTTP Status | Description |
|---|---|---|
| VALIDATION_ERROR | 400 | Invalid request payload |
| NOT_FOUND | 404 | Resource not found |
| UNAUTHORIZED | 401 | Missing or invalid API key |
| INTERNAL_ERROR | 500 | Server error |
Rate Limits
| Tier | Requests/minute | Burst |
|---|---|---|
| Standard | 1,000 | 100 |
| Enterprise | Custom | Custom |
Rate limit headers are included in all responses: X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset