API Documentation
Complete reference for the ImmutableLog REST API. Learn how to authenticate, send events, query the immutable history, and cryptographically verify the integrity of any record.
* required field or header
SDKs & Integrations
Integrate ImmutableLog directly in your language using automatic middleware for web frameworks or an HTTP client for workers and jobs.
Python
Django · FastAPI · Flask
Middleware, decorators, and requests integration.
View docs →
Node.js
Express · Fastify · NestJS
Middleware, plugins, and TypeScript decorators.
View docs →
Java
Spring · Quarkus · Micronaut
HTTP filters, interceptors, and AOP @AuditEvent.
View docs →
Go
net/http · Gin · Fiber
Middleware for net/http, Gin, and Fiber.
View docs →
Ruby
Rails · Sinatra
PHP
Laravel · Symfony
Rust
Axum · Actix
C#
ASP.NET · Minimal API
Base URL
All endpoints in this documentation are relative to the base URL below. Always use HTTPS in production to ensure data confidentiality in transit.
https://api.immutablelog.comAuthentication*
Every API request requires an access token sent in the `Authorization` header using the Bearer scheme. You can generate your token in the customer area, under API Keys. Production tokens are prefixed with `iml_live_`. Keep it secure — it authenticates all read and write operations for your tenant.
Authorization: Bearer iml_live_xxxxxxxxxxxxxxxxSecurity tip: Never expose your token in client-side code (frontend) or public repositories. Use server-side environment variables.
Idempotency-Key*
For event ingestion, we recommend sending a unique `Idempotency-Key` header per request. If the same key is resent (e.g., in a retry after a network timeout), the server recognizes the duplicate and returns the same result without creating a second event in the ledger.
Idempotency-Key: seed-42-550e8400-e29b-41d4-a716-446655440000
Request-Id: 8d0b5f06-6d1f-4d3c-9b4f-9f5a2d7b3c1aWhen to use: Recommended for automatic retries, async workers, and event-driven integrations where at-least-once delivery is guaranteed by the broker.
Client timezone (optional)
To avoid “date confusion” (UTC vs local time), you can send the client local time via headers. The server keeps canonical UTC time for ordering/proof and persists these values only as untrusted metadata for dashboard display.
X-Client-Time: 2026-02-05T21:13:22-03:00
X-Client-TZ: America/Sao_Paulo
X-Client-Offset-Minutes: -180`X-Client-Time` (ISO8601) is the most important. `X-Client-TZ` and `X-Client-Offset-Minutes` are optional and help the UI render correctly. `Request-Id` is recommended for traceability (logs/support).
curl -X POST https://api.immutablelog.com/v1/events \
-H "X-Client-Time: 2026-02-05T21:00:00-03:00" \
-H "X-Client-TZ: America/Sao_Paulo" \
-H "X-Client-Offset-Minutes: -180" \
-H "Request-Id: req-123" \
-d '{"payload":"..."}'Payload Structure
The body of each ingestion request contains two fields: `payload` and `meta`. The `payload` field is treated as an opaque string by the server — its content is not interpreted, only stored and hashed. This ensures the hash is computed over exactly what you sent, without any transformation.
payload must be a string, not an object
Serialize your object with JSON.stringify() before sending. The server treats the payload field as an opaque string to ensure the SHA-256 hash is computed over exactly what you sent.
meta.type — event classification*
The `meta.type` field classifies the severity level or category of the event. Recommended values: `error` (critical errors requiring attention), `warning` (non-critical anomalies), `info` (normal system operations), `success` (successfully completed operations). These values are used for filters and metrics in the dashboard.
meta.event_name — business event name*
The `meta.event_name` field is a human-readable label describing the business event (e.g., `payment.approved`, `user.login_failed`, `invoice.created`). Use consistent, descriptive names — they appear in the dashboard, reports, and make audits easier.
meta.service, meta.env, meta.trace_id — traceability(optional)
Additional fields in `meta` like `service`, `env`, and `trace_id` are optional but highly recommended for traceability in distributed systems. The `trace_id` field lets you correlate an ImmutableLog event with logs from other systems (e.g., APM, Datadog, OpenTelemetry).
{
"payload": "{\"id\":\"d6b6c2e5-0c1a-4b92-9a62-2f2c4c2e9a2a\",\"kind\":\"info\",\"message\":\"http.GET.user-me\",\"context\":{\"user_id\":123,\"email\":\"user@example.com\"},\"timestamp\":\"2026-02-05T12:00:00Z\"}",
"meta": {
"type": "info",
"event_name": "http.GET.user-me",
"service": "api",
"env": "prod",
"trace_id": "2c3f4f1e-7d2d-4d10-9c47-0f8d7a1b2c3d"
}
}Limit: Size limit: ~16KB per event. Larger payloads should be stored externally (e.g., S3, database) and the event should contain only the identifier and relevant metadata.
Event ingestion
Send events via `POST /v1/events`. The server computes the SHA-256 hash of the payload, stores the event, and includes it in the next block of the immutable ledger. The response returns the `tx_id` (unique transaction identifier) and the `payload_hash`, which you can use to verify integrity later.
curl -X POST https://api.immutablelog.com/v1/events \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Idempotency-Key: seed-42-550e8400-e29b-41d4-a716-446655440000" \
-H "Content-Type: application/json" \
-d '{
"payload": "{\"id\":\"d6b6c2e5-0c1a-4b92-9a62-2f2c4c2e9a2a\",\"kind\":\"info\",\"message\":\"http.GET.user-me\"}",
"meta": {
"type": "info",
"event_name": "http.GET.user-me",
"service": "api",
"env": "prod",
"trace_id": "2c3f4f1e-7d2d-4d10-9c47-0f8d7a1b2c3d"
}
}'Important: Save the `tx_id` from the response in your system. It is required to query the event individually and to generate the proof of inclusion.
Querying events
The API offers two query modes: listing with filters and pagination, or direct lookup by transaction ID. Use listing for period scans and audits; use the ID lookup when you need to verify a specific event.
Listing with filters and pagination
List events with period filters (`from_ts`, `to_ts` as Unix timestamps), type filter (`type`), and cursor-based pagination (`cursor`, `limit`). The `cursor_next` field in the response is used to fetch the next page:
curl "https://api.immutablelog.com/v1/events?from_ts=1704067200&to_ts=1704153600&limit=100&type=info" \
-H "Authorization: Bearer YOUR_TOKEN"Lookup by transaction ID
Fetch a specific event by its `tx_id`. The response includes the original payload, the computed hash, and the block metadata where it was included:
curl "https://api.immutablelog.com/v1/events/a1b2c3d4-e5f6-7890-abcd-ef1234567890" \
-H "Authorization: Bearer YOUR_TOKEN"{
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"timestamp": 1704067200,
"payload": "{\"id\":\"d6b6c2e5\",\"kind\":\"info\",\"message\":\"Event received\"}",
"payload_parsed": { "id": "d6b6c2e5", "kind": "info", "message": "Event received" },
"payload_hash": "4f2b8e9a3c5d7f1e2a4b6c8d0e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d5e7",
"meta": {
"tenant_id": "...",
"type": "info",
"event_name": "Event received"
}
}Statistics
The statistics endpoint returns event volume grouped by day, with breakdown by type (`success`, `info`, `warning`, `error`). Useful for operational dashboards, audit reports, and volume anomaly monitoring.
Mode 1: Last N days
Parameter `days`: returns the last N days from the moment of the query. Maximum: 7 days. Use this mode for real-time dashboards.
curl "https://api.immutablelog.com/v1/events/stats?days=7&tz_offset_minutes=-180" \
-H "Authorization: Bearer YOUR_TOKEN"Mode 2: Custom period (from_ts/to_ts)
Parameters `from_ts` and `to_ts`: custom period using Unix timestamps (seconds). Maximum range is 7 days between `from_ts` and `to_ts`. Use this mode for historical reports of specific periods.
curl "https://api.immutablelog.com/v1/events/stats?from_ts=1769904000&to_ts=1770422399&tz_offset_minutes=-180" \
-H "Authorization: Bearer YOUR_TOKEN"from_ts=1769904000 is 02/01/2026 00:00 UTC, to_ts=1770422399 is 02/07/2026 23:59 UTC (7 days)
{
"stats": [
{
"date": "2026-02-01",
"count": 8186,
"timestamp": 1769904000,
"by_type": {
"success": 4523,
"info": 2103,
"error": 1203,
"warning": 357
}
},
{
"date": "2026-02-02",
"count": 7892,
"timestamp": 1769990400,
"by_type": { "success": 4201, "info": 2145, "error": 1198, "warning": 348 }
}
],
"total": 54600,
"total_by_type": {
"success": 30003,
"info": 15087,
"error": 6657,
"warning": 2853
}
}Range limit: Maximum 7 days between from_ts and to_ts.
Retention: Respects the plan's retention period. Free plan: 7 days. Paid plans: as contracted. Queries outside the retention window return empty data without error.
Timezone: tz_offset_minutes groups events by day in local timezone.
Proof of inclusion
Verifiable`GET /v1/events/:tx_id/proof` returns the Merkle proof that cryptographically demonstrates a specific event was included in the ledger exactly as submitted, without modification. This proof is self-contained and can be verified by any third party without trusting ImmutableLog.
The proof is cryptographically verifiable and does not depend on trusting the system operator. Ideal for external audits, contractual disputes, and regulatory compliance.
curl "https://api.immutablelog.com/v1/events/a1b2c3d4-e5f6-7890-abcd-ef1234567890/proof" \
-H "Authorization: Bearer YOUR_TOKEN"{
"tx_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"tx_hash": "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
"payload_hash": "4f2b8e9a3c5d7f1e2a4b6c8d0e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d5e7",
"block_index": 48291,
"block_hash": "0x9a2e8f7c4b1d3a5e7f9b1c3d5e7f9a1b3c5d7e9f1a3b5c7d9e1f3a5b7c9d1e",
"prev_hash": "0x8f1c2a4b6d8e0f2a4c6e8f0a2c4e6f8a0c2e4f6a8c0e2f4a6c8e0f2a4c6e8",
"merkle_root": "0x7d9e1f3a5b7c9d1e3f5a7b9c1d3e5f7a9b1c3d5e7f9a1b3c5d7e9f1a3b5c",
"merkle_path": [
{ "hash": "0xabc123...", "position": "left" },
{ "hash": "0xdef456...", "position": "right" },
{ "hash": "0x789abc...", "position": "left" }
]
}How to verify: How to verify: recompute the Merkle root by combining the event's `tx_hash` with the hashes from `merkle_path` (respecting `left`/`right` positions). If the result matches the block's `merkle_root`, the inclusion is proven.
API Responses
The API follows standard REST conventions. All response bodies are JSON. Below are the main HTTP status codes you may encounter and what to do in each case.
202 — Accepted
{
"ok": true,
"tx_id": "3f227a2d-ae7b-4fde-95a5-313197cc6b3a",
"payload_hash": "00cf048489f716479f124654cdb7c3551a05b46a1245eaaac34bd2fe933f2fd3",
"status": "accepted",
"duplicate": false,
"request_id": "f7ba7cfe-bb18-454c-af2f-19404719b421"
}The event was successfully accepted and will be included in the next ledger block. Save the returned `tx_id` — it is the permanent event identifier required for future queries and inclusion proofs.
401 — Unauthorized
{
"ok": false,
"reason": "unauthorized"
}Token missing, invalid, or expired. Check that the `Authorization: Bearer <token>` header is present and correct. If the token has expired or been revoked, generate a new one in the customer area.
403 — Forbidden
{
"ok": false,
"reason": "forbidden"
}Valid token, but insufficient permission for this operation. Common causes: insufficient scope for the accessed endpoint or inactive/suspended subscription. Check your contracted plan and API key permissions in the customer area.
429 — Monthly limit exceeded
{
"ok": false,
"reason": "monthly_limit_exceeded: 50000/50000 events used this billing cycle"
}The plan's event limit for the current billing cycle has been reached. The `reason` field indicates the volume used (e.g., `50000/50000`). Upgrade your plan or wait for the next billing cycle to resume ingestion.
This documentation reflects the current API behavior. For production integrations or specific questions, contact the support team.
