API Endpoints
This document provides detailed information about all available Logstyx API endpoints.
Base URL
https://your-domain.com/apiFor local development:
http://localhost:5000/apiPOST /v1/logs
Submit log entries to your Logstyx project. This is the primary endpoint for sending application logs.
Endpoint
POST /v1/logsRate Limits
- Rate: 20 requests per second per IP address
- Burst: 50 requests can burst above the rate limit
- Response on limit exceeded:
503 Service Unavailableor429 Too Many Requests
Headers
Required Headers
Content-Type: application/jsonOptional Headers (Server Clients Only)
timestamp: <unix_timestamp_in_milliseconds>
signature: <hmac_sha256_signature>These headers are required for server-side authentication. See Authentication for details.
Browser Headers (Automatic)
Origin: <browser_origin>This header is automatically sent by browsers and used for authentication.
Request Body
Required Fields
| Field | Type | Description |
|---|---|---|
level | string | Log level. Must be one of: info, warning, error, critical |
projectId | string | Your Logstyx project ID |
data | object | The actual log data and message |
Optional Fields
| Field | Type | Description | Default |
|---|---|---|---|
device | object | Identifier for the device/server sending the log | {} |
context | object | Additional contextual information | {} |
appid | string | Application ID (required for mobile clients) | null |
Request Body Schema
{
"level": "info|warning|error|critical",
"projectId": "string",
"device": {
"type": "iPhone 15 Pro",
"origin": null,
"os": null,
"platform": null,
"browser": null,
"screen": null
},
"context": {
"key": "value"
},
"data": {
"message": "string",
"additional": "fields"
},
"appid": "string (mobile only)"
}Response
All requests return a 200 OK status regardless of success or failure. The log is queued for asynchronous processing.
{
"status": "queued"
}Log Levels
Logstyx supports four log levels, ordered by severity:
| Level | Description | Use Case |
|---|---|---|
info | Informational messages | General application events, user actions |
warning | Warning messages | Potential issues that don't stop execution |
error | Error messages | Runtime errors, failed operations |
critical | Critical messages | System failures, data corruption, security breaches |
Examples
Example 1: Basic Info Log (Browser)
curl -X POST https://your-domain.com/api/v1/logs \
-H "Content-Type: application/json" \
-H "Origin: https://yourapp.com" \
-d '{
"level": "info",
"projectId": "proj_abc123xyz",
"data": {
"message": "User completed onboarding",
"userId": "user_12345",
"completedSteps": 5
}
}'Example 2: Error Log with Context (Browser)
curl -X POST https://your-domain.com/api/v1/logs \
-H "Content-Type: application/json" \
-H "Origin: https://yourapp.com" \
-d '{
"level": "error",
"projectId": "proj_abc123xyz",
"device": {
"type": "browser",
"origin": null,
"os": "Windows",
"platform": null,
"browser": "Chrome",
"screen": "1900x1600"
},
"context": {
"userId": "user_12345",
"sessionId": "sess_xyz789",
"route": "/checkout"
},
"data": {
"message": "Payment processing failed",
"errorCode": "PAYMENT_DECLINED",
"amount": 99.99,
"currency": "USD",
"paymentMethod": "credit_card"
}
}'Example 3: Mobile App Log
curl -X POST https://your-domain.com/api/v1/logs \
-H "Content-Type: application/json" \
-d '{
"level": "warning",
"projectId": "proj_abc123xyz",
"appid": "com.yourcompany.app.ios",
"device": {
"type": "iPhone 15 Pro",
"origin": null,
"os": null,
"platform": null,
"browser": null,
"screen": null
},
"context": {
"userId": "user_12345",
"appVersion": "2.5.1"
},
"data": {
"message": "Network request timeout",
"endpoint": "/api/v1/products",
"duration": 30000
}
}'Example 4: Server Log with Signature
const crypto = require('crypto');
const axios = require('axios');
async function sendServerLog() {
const projectId = 'proj_abc123xyz';
const projectSecret = 'your_secret_key';
const timestamp = Date.now();
const body = {
level: 'critical',
projectId: projectId,
device: {
"type": "node",
"origin": null,
"os": "linux",
"platform": null,
"browser": null,
"screen": null
},
context: {
service: 'database',
region: 'us-east-1'
},
data: {
message: 'Database connection pool exhausted',
activeConnections: 100,
maxConnections: 100,
queuedRequests: 47
}
};
// Generate signature
const payload = {
level: body.level,
projectId: body.projectId,
device: body.device,
context: body.context,
data: body.data
};
const params = JSON.stringify(payload);
const hashString = projectId + params + Math.floor(timestamp);
const signature = crypto
.createHmac('SHA256', projectSecret)
.update(hashString)
.digest('hex')
.toUpperCase();
// Send request
const response = await axios.post(
'https://your-domain.com/api/v1/logs',
body,
{
headers: {
'Content-Type': 'application/json',
'timestamp': timestamp.toString(),
'signature': signature
}
}
);
return response.data;
}Example 5: Python Server Client
import hmac
import hashlib
import json
import time
import requests
def send_log(level, message, additional_data=None):
project_id = 'proj_abc123xyz'
project_secret = 'your_secret_key'
timestamp = int(time.time() * 1000)
body = {
'level': level,
'projectId': project_id,
'device': {
"type": "python",
"origin": null,
"os": "linux",
"platform": null,
"browser": null,
"screen": null
},
'context': {
'environment': 'production',
'service': 'data-processor'
},
'data': {
'message': message,
**(additional_data or {})
}
}
# Generate signature
payload = {
'level': body['level'],
'projectId': body['projectId'],
'device': body['device'],
'context': body['context'],
'data': body['data']
}
params = json.dumps(payload, separators=(',', ':'))
hash_string = f"{project_id}{params}{int(timestamp)}"
signature = hmac.new(
project_secret.encode('utf-8'),
hash_string.encode('utf-8'),
hashlib.sha256
).hexdigest().upper()
# Send request
response = requests.post(
'https://your-domain.com/api/v1/logs',
json=body,
headers={
'Content-Type': 'application/json',
'timestamp': str(timestamp),
'signature': signature
}
)
return response.json()
# Usage
send_log('error', 'Failed to process batch', {
'batchId': 'batch_789',
'recordsProcessed': 1543,
'recordsFailed': 12,
'errorRate': 0.0078
})Example 6: Go Server Client
package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"strings"
"time"
)
type LogData struct {
Message string `json:"message"`
Extra map[string]interface{} `json:"extra"` // Standard JSON nesting
}
type Device struct {
Type string `json:"type"`
Origin string `json:"origin"`
Os string `json:"os"`
Platform string `json:"platform"`
}
type LogRequest struct {
Level string `json:"level"`
ProjectID string `json:"projectId"`
Device Device `json:"device"` // Changed from "data" to "device" to avoid conflict
Context map[string]interface{} `json:"context"`
Data LogData `json:"data"`
}
func sendLog(projectID, projectSecret, level string, device Device, message string, context, extra map[string]interface{}) error {
timestamp := time.Now().UnixNano() / int64(time.Millisecond)
req := LogRequest{
Level: level,
ProjectID: projectID,
Device: device,
Context: context,
Data: LogData{
Message: message,
Extra: extra,
},
}
// Generate signature using the request struct directly to ensure consistency
payloadJSON, _ := json.Marshal(req)
hashString := fmt.Sprintf("%s%s%d", projectID, string(payloadJSON), timestamp)
h := hmac.New(sha256.New, []byte(projectSecret))
h.Write([]byte(hashString))
signature := strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
// Send request
httpReq, err := http.NewRequest("POST", "https://your-domain.com/api/v1/logs", bytes.NewBuffer(payloadJSON))
if err != nil {
return err
}
httpReq.Header.Set("Content-Type", "application/json")
httpReq.Header.Set("timestamp", fmt.Sprintf("%d", timestamp))
httpReq.Header.Set("signature", signature)
client := &http.Client{Timeout: 10 * time.Second}
resp, err := client.Do(httpReq)
if err != nil {
return err
}
defer resp.Body.Close()
fmt.Printf("Log sent! Status: %s\n", resp.Status)
return nil
}
func main() {
context := map[string]interface{}{
"service": "auth",
"region": "us-west-2",
}
extra := map[string]interface{}{
"userId": "user_12345",
"attemptNum": 3,
}
// Use the struct instead of a map for type safety
device := Device{
Type: "go",
}
err := sendLog(
"proj_abc123xyz",
"your_secret_key",
"warning",
device,
"Multiple failed login attempts",
context,
extra,
)
if err != nil {
fmt.Println("Error:", err)
}
}Example 7: Batch Logging
While the API doesn't support batch endpoints, you can implement client-side batching:
class LogBatcher {
constructor(projectId, projectSecret, batchSize = 10, flushInterval = 5000) {
this.projectId = projectId;
this.projectSecret = projectSecret;
this.batchSize = batchSize;
this.buffer = [];
// Flush periodically
setInterval(() => this.flush(), flushInterval);
}
add(level, data, context = {}, device = 'server') {
this.buffer.push({ level, data, context, device });
if (this.buffer.length >= this.batchSize) {
this.flush();
}
}
async flush() {
if (this.buffer.length === 0) return;
const logs = [...this.buffer];
this.buffer = [];
// Send all logs concurrently
await Promise.all(
logs.map(log => this.sendLog(log))
);
}
async sendLog({ level, data, context, device }) {
// Implementation from Example 4
// ... signature generation and request ...
}
}
// Usage
const batcher = new LogBatcher('proj_abc123xyz', 'your_secret_key');
// Logs are batched and sent automatically
batcher.add('info', { message: 'User login' });
batcher.add('info', { message: 'Page view' });
batcher.add('error', { message: 'API error' });Field Specifications
level Field
Can be one of these strings, but you can create your own
infowarningerrorcritical
projectId Field
- Type: String
- Obtained from: Logstyx dashboard after project creation
device Field
- Type: Object
- Optional: Yes
context Field
- Type: Object
- Optional: Yes
- Purpose: Store contextual metadata that helps filter and search logs
- Common fields:
userId: User identifiersessionId: Session identifierrequestId: Request trace IDenvironment:production,staging,developmentservice: Service name in microservices architectureversion: Application version
data Field
- Type: Object
- Required: Yes
- Purpose: Store the actual log content
- Common fields:
title: Human-readable log title (recommended)message: Human-readable log message (recommended)- Any additional structured data relevant to the log
appid Field
- Type: String
- Required for: Mobile clients only
- Format: Reverse domain notation (e.g.,
com.company.app.platform) - Purpose: Mobile client authentication
Best Practices
1. Structured Logging
Use consistent field names across your application:
{
"level": "error",
"projectId": "proj_abc123xyz",
"context": {
"userId": "user_12345",
"requestId": "req_xyz789"
},
"data": {
"message": "Database query failed",
"operation": "SELECT",
"table": "users",
"duration": 5234,
"error": "Connection timeout"
}
}2. Include Relevant Context
Always include context that helps debugging:
{
"context": {
"environment": "production",
"service": "payment-service",
"version": "2.5.1",
"region": "us-east-1",
"userId": "user_12345",
"sessionId": "sess_abc123"
}
}3. Use Appropriate Log Levels
info: Normal operations, user actionswarning: Deprecated features, non-critical issueserror: Failed operations that are handledcritical: System failures requiring immediate attention
4. Avoid Logging Sensitive Data
Never log:
- Passwords or API keys
- Credit card numbers
- Personal identification numbers
- Authentication tokens
- Social security numbers
5. Implement Client-Side Batching
Reduce network overhead by batching logs when possible (see Example 7).
6. Handle Rate Limits
Implement exponential backoff when rate limits are hit:
async function sendLogWithRetry(logData, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
try {
await sendLog(logData);
return;
} catch (error) {
if (error.response?.status === 429 || error.response?.status === 503) {
const delay = Math.pow(2, i) * 1000; // Exponential backoff
await new Promise(resolve => setTimeout(resolve, delay));
} else {
throw error;
}
}
}
}Troubleshooting
Issue: Logs not appearing in dashboard
Possible causes:
- Authentication failure (wrong project ID, invalid origin/appid, incorrect signature)
- Rate limiting
- Invalid request format
Solutions:
- Verify project ID and authentication credentials
- Check authentication method matches client type
- Ensure request body follows the correct schema
- Check for rate limit responses
Issue: 429 or 503 responses
Cause: Rate limit exceeded (more than 20 requests/second per IP)
Solutions:
- Implement client-side batching
- Add exponential backoff retry logic
- Reduce logging frequency
- Use log sampling for high-volume events
Issue: Signature validation fails (server clients)
Common mistakes:
- Wrong field order in payload
- Signature not in uppercase
- Timestamp not converted to integer
- Extra spaces in JSON serialization
- Using wrong project secret
Solution: Carefully review the signature generation algorithm in Authentication