Overview
Logsync provides a simple, powerful API for adding tamper-proof audit logging to any application. Every event you log is cryptographically linked to the previous event using SHA-256 hashes, creating an immutable chain that makes tampering immediately detectable.
Fast Integration
Integrate in under 5 minutes with our SDKs. One API call to log events.
Tamper-Proof
SHA-256 hash chain ensures data integrity. Any modification is detectable.
Compliance Ready
Meet SOC 2, HIPAA, GDPR, and PCI DSS audit logging requirements.
How It Works
- 1Create a Project - Sign up and create a project in the dashboard to get your API key.
- 2Install an SDK - Choose from Node.js, Python, Go, Java, .NET, PHP, or Ruby.
- 3Log Events - Call the log method whenever a significant action occurs in your app. Events are instantly accepted and processed asynchronously.
- 4Search & Verify - Use the dashboard to search events and verify chain integrity.
High-Performance Async Processing
Events are immediately accepted and queued for processing (~10-20ms response time). Background workers process events within seconds, maintaining hash chain integrity. This architecture supports 10,000+ events/second ingestion.
Quick Start
Get up and running in under 5 minutes. Here's a complete example:
Install the SDK
Run this command:
npm install logsyncInitialize the Client
Initialize the SDK client:
import { Logsync } from 'logsync';
// Initialize the client with your API key
const audit = new Logsync('ls_your_api_key');
// Or with custom options
const audit = new Logsync('ls_your_api_key', {
baseUrl: 'https://logsync.dev', // Custom endpoint (optional)
timeout: 30000, // Request timeout in ms
retries: 3, // Auto-retry failed requests
});Log Events
Log your first events:
// Basic event logging
await audit.log({
actorId: 'user_123',
action: 'document.created',
resource: 'doc_456',
});
// Full event with all fields
await audit.log({
actorId: 'user_123', // Required: who performed the action
actorType: 'user', // Optional: type of actor
action: 'document.shared', // Required: what action was performed
resource: 'doc_456', // Required: what resource was affected
resourceType: 'document', // Optional: type of resource
timestamp: new Date(), // Optional: when it happened (defaults to now)
ip: '192.168.1.1', // Optional: client IP address
metadata: { // Optional: additional context
sharedWith: ['team@company.com'],
permission: 'view',
expiresAt: '2024-12-31T23:59:59Z'
}
});
// Response (202 Accepted)
{
success: true,
status: 'accepted',
message: 'Event accepted for processing',
queuePosition: 42
}
// Events appear in queries within ~5 secondsAuthentication
All API requests require authentication using an API key. You can create API keys in the dashboard after signing up.
Using the API Key
Include your API key in the X-API-Key header:
curl -X POST https://logsync.dev/api/ingest \
-H "Content-Type: application/json" \
-H "X-API-Key: ls_your_api_key" \
-d '{"actorId": "user_123", "action": "login", "resource": "session_456"}'Keep Your API Key Secret
Never expose your API key in client-side code, public repositories, or logs. Use environment variables and server-side code to make API calls.
Event Schema
Each audit event captures who did what, to what, and when. Here's the complete schema:
| Field | Type | Required | Description |
|---|---|---|---|
| actorId | string | Required | Identifier of who performed the action (user ID, service name, etc.) |
| action | string | Required | The action that was performed (e.g., "document.created", "user.login") |
| resource | string | Required | Identifier of the resource being acted upon |
| actorType | string | Optional | Type of actor (e.g., "user", "admin", "system", "api") |
| resourceType | string | Optional | Type of resource (e.g., "document", "user", "order") |
| timestamp | ISO 8601 | Optional | When the event occurred. Defaults to current time if not provided. |
| ip | string | Optional | Client IP address. Auto-detected from request headers if not provided. |
| metadata | object | Optional | Additional context as a JSON object (max 64KB) |
Naming Conventions
Action Names
Use dot notation for hierarchical actions:
user.createddocument.sharedorder.payment.completedsettings.security.2fa.enabled
Actor Types
Common actor type values:
user- Regular useradmin- Administratorsystem- Automated processapi- External API client
SDKs
Official SDKs are available for all major programming languages. Each SDK includes automatic retries, type definitions, and idiomatic patterns for the language.
Node.js
npm install logsync
TypeScript support, Promise-based API
Python
pip install logsync
Type hints, async support
Go
go get logsync-go
Idiomatic Go, context support
Java
Maven/Gradle
Builder pattern, Java 11+
.NET
dotnet add package
Async/await, .NET 6+
PHP
composer require
PSR-4, PHP 8.0+
Ruby
gem install
Ruby 3.0+, Rails compatible
REST API
cURL / Any language
Use directly from any HTTP client
REST API
The REST API can be used directly from any language or HTTP client. Base URL: https://logsync.dev
/api/ingest— Log an audit eventRequest Headers
Content-Type: application/json
X-API-Key: ls_your_api_keyRequest Body
{
"actorId": "user_123",
"actorType": "user",
"action": "document.created",
"resource": "doc_456",
"resourceType": "document",
"timestamp": "2024-01-15T10:30:00Z",
"ip": "192.168.1.1",
"metadata": {
"title": "Q4 Report",
"size": 1024000
}
}Response (202 Accepted)
{
"success": true,
"status": "accepted",
"message": "Event accepted for processing",
"queuePosition": 42
}Events are processed asynchronously and appear in queries within ~5 seconds.
Response Headers
X-Event-Status: accepted
X-Queue-Position: 42
X-Monthly-Limit: 25000
X-Monthly-Used: 1250
X-Monthly-Queued: 15
X-Monthly-Usage-Percent: 5/api/events— Query events with paginationQuery Parameters
| Parameter | Type | Description |
|---|---|---|
| limit | number | Max events to return (1-1000, default: 100) |
| cursor | string | Pagination cursor from previous response |
| actorId | string | Filter by actor ID (partial match) |
| action | string | Filter by action (partial match) |
| resource | string | Filter by resource (partial match) |
| startDate | ISO 8601 | Filter events after this date |
| endDate | ISO 8601 | Filter events before this date |
| order | string | "asc" or "desc" (default: "desc") |
Example Request
curl -X GET "https://logsync.dev/api/events?limit=50&actorId=user_123" \
-H "X-API-Key: ls_your_api_key"Response (200 OK)
{
"success": true,
"events": [
{
"id": "12345",
"actorId": "user_123",
"action": "document.created",
"resource": "doc_456",
"timestamp": "2024-01-15T10:30:00Z",
"hash": "a1b2c3d4...",
"prevHash": "x9y8z7..."
}
],
"pagination": {
"limit": 50,
"hasMore": true,
"nextCursor": "12344",
"total": 1250,
"order": "desc"
}
}/api/events/:id— Get a single event by IDExample Request
curl -X GET "https://logsync.dev/api/events/12345" \
-H "X-API-Key: ls_your_api_key"Response (200 OK)
{
"success": true,
"event": {
"id": "12345",
"actorId": "user_123",
"action": "document.created",
"resource": "doc_456",
"timestamp": "2024-01-15T10:30:00Z",
"hash": "a1b2c3d4...",
"prevHash": "x9y8z7..."
},
"chain": {
"previous": { "id": "12344", "hash": "x9y8z7...", "timestamp": "..." },
"next": { "id": "12346", "hash": "e5f6g7...", "timestamp": "..." },
"isChainStart": false,
"isChainEnd": false
}
} The chain object provides context for integrity verification.
/api/events/verify— Verify integrity of event chainRequest Body
{
"eventId": "12345", // Verify single event (optional)
"startId": "100", // Verify range start (optional)
"endId": "200", // Verify range end (optional)
"limit": 1000 // Max events to verify (default: 1000)
}If no parameters provided, verifies the most recent 1000 events.
Example Request
curl -X POST "https://logsync.dev/api/events/verify" \
-H "Content-Type: application/json" \
-H "X-API-Key: ls_your_api_key" \
-d '{"limit": 1000}'Response (200 OK)
{
"success": true,
"valid": true,
"verified": 1000,
"chainIntact": true,
"issues": [],
"range": {
"start": { "id": "1", "timestamp": "...", "hash": "..." },
"end": { "id": "1000", "timestamp": "...", "hash": "..." }
},
"summary": "Successfully verified 1000 events. Hash chain is intact."
}Response with Issues
{
"success": true,
"valid": false,
"verified": 500,
"chainIntact": false,
"issues": [
{
"eventId": "123",
"type": "hash_mismatch",
"message": "Event 123 hash does not match. Data may have been tampered.",
"expected": "a1b2c3...",
"actual": "x9y8z7..."
}
],
"summary": "Found 1 integrity issue(s) in 500 events."
} Issue types: hash_mismatch, chain_break, missing_link
Cryptographic Hash Chain
Every event in Logsync is cryptographically linked to form a tamper-evident chain. This ensures that any modification to historical events is immediately detectable.
How It Works
Event Hashing
Each event's content is hashed using SHA-256, including: actorId, action, resource, timestamp, metadata, and the previous event's hash.
Chain Linking
By including the previous hash, each event is cryptographically linked to all events before it, forming an unbreakable chain.
Tamper Detection
If any event is modified, its hash changes, breaking the link to the next event. Verification instantly detects the discrepancy.
Chain Structure
Each event contains the hash of the previous event, creating an unbreakable chain back to the first event.
Rate Limits
Rate limits are applied per API key to ensure fair usage and system stability. Higher plans include increased rate limits. With our async processing, you can burst at high rates while events are queued and processed in the background.
| Plan | Requests/Minute | Burst Limit |
|---|---|---|
| Free | 100/min | 10/sec |
| Starter | 500/min | 50/sec |
| Growth | 2,000/min | 200/sec |
| Pro | 10,000/min | 1,000/sec |
Rate Limit Headers
Every response includes headers to help you track your rate limit status:
X-RateLimit-Limit: 1000 # Your plan's limit
X-RateLimit-Remaining: 950 # Requests remaining
X-RateLimit-Reset: 1705312800 # Unix timestamp when limit resetsError Handling
The API uses conventional HTTP status codes to indicate success or failure. Error responses include a message explaining what went wrong.
| Code | Name | Description |
|---|---|---|
| 202 | Accepted | Event accepted for async processing (success) |
| 400 | Bad Request | Invalid request body or missing required fields |
| 401 | Unauthorized | Missing or invalid API key |
| 402 | Payment Required | Monthly event limit exceeded, upgrade required |
| 403 | Forbidden | API key does not have access to this resource |
| 404 | Not Found | Resource not found |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Something went wrong on our end |
| 503 | Service Unavailable | Service temporarily unavailable, retry later |
Error Response Format
{
"statusCode": 400,
"message": "actorId is required and must be a string"
}Best Practices
Log Meaningful Events
Focus on security-relevant and compliance-important actions: authentication, authorization changes, data access, configuration changes, and administrative actions.
Use Consistent Naming
Establish naming conventions for actions (e.g., resource.verb format) and stick to them. This makes searching and filtering much easier.
Include Relevant Metadata
Add context that will be useful during investigations: IP addresses, user agents, affected field names, before/after values for changes.
Don't Log Sensitive Data
Never include passwords, API keys, credit card numbers, or PII in metadata. Log references (IDs) instead of actual sensitive values.
Handle Failures Gracefully
Our SDKs retry automatically, but always handle logging failures gracefully. Audit logging should never break your application's core functionality.
Understand Async Processing
Events are accepted immediately (202 response) and processed within seconds. If you need to query recently logged events, allow a few seconds for processing to complete.
Verify Integrity Regularly
Use the dashboard or API to periodically verify your audit chain integrity. This proves your logs haven't been tampered with and is often required for compliance.
Frequently Asked Questions
How do I know when my event is processed?
When you log an event, you receive a 202 Accepted response with a queuePosition. The event is then processed asynchronously.
Options to know when processing is complete:
- Query after delay: Wait ~5 seconds, then query
GET /api/eventsto find your event - Check by metadata: Include a unique
requestIdin metadata, then query for it - Dashboard: Events appear in the dashboard automatically once processed
Coming soon: Webhook notifications for event processing completion. if you need this feature urgently.
Can I query events immediately after logging?
Short answer: No, there's a brief delay (~5 seconds) between logging and queryability.
Why? Logsync uses asynchronous processing to achieve high throughput (10,000+ events/second). Events are queued immediately (your 202 Accepted response) and batch-processed every 5 seconds for efficiency.
Timeline:
Pro tip: If you need to show a "logged" confirmation in your UI, trust the 202 Accepted response. For audit/compliance purposes, the slight delay doesn't matter.
What's the SLA for processing time?
| Metric | Target | Notes |
|---|---|---|
| Ingest response time | < 50ms | Time to receive 202 Accepted |
| Processing latency | ~5 seconds | Time until queryable |
| Max processing latency | < 30 seconds | 99th percentile |
| Queue reliability | 99.9% | Events accepted are guaranteed processed |
What if processing fails? Events that fail processing are moved to a Dead Letter Queue (DLQ) and can be manually retried via the admin dashboard. You'll never lose an accepted event.
Enterprise SLA: Pro plans include SLA guarantees with credits. View plans
Is the hash chain maintained with async processing?
Yes, absolutely. Each project has its own dedicated queue, and events are processed in strict FIFO (First-In-First-Out) order.
How it works:
- Your event is added to your project's queue
- Worker acquires a lock on your project's queue
- Events are processed sequentially, computing each hash with the previous event's hash
- Entire batch is written atomically to the database
This guarantees the same hash chain integrity as synchronous processing, but with 100x better throughput.
What happens if the server is down when I log an event?
Our SDKs automatically retry failed requests with exponential backoff:
For extended outages, you should implement local buffering in your application to queue events and replay them when the service recovers.
Best practice: Always handle the SDK's failure response gracefully. Audit logging should never crash your main application.
Ready to Get Started?
Create a free account to get your API key and start logging tamper-proof audit events in minutes.