API Reference
AtomicEdge provides API endpoints for log ingestion and programmatic integration. This reference covers authentication, endpoints, request formats, and response handling.
Authentication
API requests require Bearer token authentication. Include the token in the Authorization header:
Authorization: Bearer YOUR_API_TOKEN_HERE
Obtain API tokens from the dashboard under Account Settings > API Access. Tokens should be kept secure and rotated regularly.
Log Ingestion Endpoints
WAF Security Logs
Submit WAF security event logs for centralized monitoring.
Endpoint: POST /api/vector/waf
Content-Type: application/json
Request Format (single event):
{
"timestamp_ms": 1699564820000,
"host": "example.com",
"client_ip": "203.0.113.45",
"uri": "/admin.php",
"method": "GET",
"waf_file": "/etc/caddy/coreruleset/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf",
"rule_id": "920100",
"severity": "CRITICAL",
"msg": "Invalid HTTP Request Line"
}
Request Format (batch):
[
{
"timestamp_ms": 1699564820000,
"host": "example.com",
"client_ip": "203.0.113.45",
"uri": "/admin.php",
"method": "GET",
"waf_file": "/etc/caddy/coreruleset/rules/REQUEST-920-PROTOCOL-ENFORCEMENT.conf",
"rule_id": "920100",
"severity": "CRITICAL",
"msg": "Invalid HTTP Request Line"
},
{
"timestamp_ms": 1699564821000,
"host": "example.com",
"client_ip": "203.0.113.45",
"uri": "/login.php",
"method": "POST",
"waf_file": "/etc/caddy/wordpress/rules/WORDPRESS-ATTACKS.conf",
"rule_id": "WP001",
"severity": "WARNING",
"msg": "WordPress Login Attempt"
}
]
Required Fields:
timestamp_ms(integer): Unix timestamp in millisecondshost(string): Domain name of the protected siteclient_ip(string): Source IP address of the requesturi(string): Request URI including query stringmethod(string): HTTP method (GET, POST, etc.)waf_file(string): WAF rule file path that triggeredrule_id(string): Specific rule ID that matchedseverity(string): Event severity (CRITICAL, WARNING, NOTICE)msg(string): Human-readable message describing the event
Optional Fields:
user_agent(string): Client User-Agent headerreferer(string): HTTP Referer headermatched_var(string): Specific variable that matched the rulematched_data(string): Actual data that triggered the rule
Response (success):
{
"message": "Processed 2 log entries",
"processed": 2
}
Response (partial success – HTTP 207):
{
"message": "Processed 1 of 2 log entries",
"processed": 1,
"errors": [
{
"index": 1,
"error": "Invalid timestamp format"
}
]
}
Response (error – HTTP 400):
{
"message": "Invalid request format",
"errors": [
"Field 'timestamp_ms' is required"
]
}
Access Logs
Submit access logs for traffic analysis and monitoring.
Endpoint: POST /api/vector/access
Content-Type: application/json
Request Format (single entry):
{
"timestamp": 1699564820,
"host": "example.com",
"client_ip": "203.0.113.45",
"uri": "/index.html",
"method": "GET",
"status": 200,
"bytes_sent": 4096,
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
}
Request Format (batch):
[
{
"timestamp": 1699564820,
"host": "example.com",
"client_ip": "203.0.113.45",
"uri": "/index.html",
"method": "GET",
"status": 200,
"bytes_sent": 4096,
"user_agent": "Mozilla/5.0..."
},
{
"timestamp": 1699564821,
"host": "example.com",
"client_ip": "198.51.100.30",
"uri": "/api/data",
"method": "POST",
"status": 201,
"bytes_sent": 256,
"user_agent": "CustomClient/1.0"
}
]
Required Fields:
timestamp(integer): Unix timestamp in secondshost(string): Domain nameclient_ip(string): Source IP addressuri(string): Request URImethod(string): HTTP methodstatus(integer): HTTP status codebytes_sent(integer): Response size in bytes
Optional Fields:
user_agent(string): Client User-Agentreferer(string): HTTP Refererrequest_time(float): Request processing time in secondsupstream_time(float): Backend response time in seconds
Response (success):
{
"message": "Processed 2 log entries",
"processed": 2
}
Error Handling
HTTP Status Codes
- 200 OK: Request processed successfully
- 207 Multi-Status: Partial success (some entries processed, some failed)
- 400 Bad Request: Invalid request format or missing required fields
- 401 Unauthorized: Missing or invalid authentication token
- 429 Too Many Requests: Rate limit exceeded
- 500 Internal Server Error: Server-side processing error
Error Response Format
All error responses follow this structure:
{
"message": "Brief error description",
"errors": [
"Detailed error 1",
"Detailed error 2"
]
}
For batch processing with partial failures (HTTP 207):
{
"message": "Processed X of Y entries",
"processed": X,
"errors": [
{
"index": 2,
"error": "Invalid timestamp format"
},
{
"index": 5,
"error": "Missing required field 'host'"
}
]
}
Rate Limiting
API endpoints enforce rate limits to prevent abuse:
- WAF logs: 100 requests per minute per token
- Access logs: 100 requests per minute per token
Rate limit headers are included in responses:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 87
X-RateLimit-Reset: 1699564920
When rate limited, response includes:
{
"message": "Rate limit exceeded",
"retry_after": 42
}
Wait the specified retry_after seconds before retrying.
Best Practices
Batching
Submit logs in batches rather than individual requests:
- Reduces API call overhead
- Improves rate limit efficiency
- Recommended batch size: 50-100 entries per request
Example batch submission:
curl -X POST https://api.atomicedge.io/api/vector/waf \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d @batch.json
Error Handling
Implement robust error handling:
- Check HTTP status code
- Parse error response for details
- Retry with exponential backoff for 5xx errors
- Do not retry 4xx errors without fixing the issue
- Log failed submissions for manual review
Example retry logic:
import time
import requests
def submit_logs(logs, token, max_retries=3):
url = "https://api.atomicedge.io/api/vector/waf"
headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
for attempt in range(max_retries):
try:
response = requests.post(url, json=logs, headers=headers)
if response.status_code == 200:
return response.json()
elif response.status_code in [500, 502, 503, 504]:
# Server error - retry with backoff
wait = (2 ** attempt) + random.random()
time.sleep(wait)
continue
else:
# Client error - do not retry
response.raise_for_status()
except requests.exceptions.RequestException as e:
if attempt == max_retries - 1:
raise
wait = (2 ** attempt) + random.random()
time.sleep(wait)
Authentication
Securely manage API tokens:
- Store tokens in environment variables or secure vaults
- Never commit tokens to version control
- Rotate tokens regularly (every 90 days recommended)
- Use separate tokens for different applications
- Revoke compromised tokens immediately
Timestamp Handling
Ensure accurate timestamps:
- Use NTP to synchronize system clocks
- WAF logs require milliseconds (
timestamp_ms) - Access logs use seconds (
timestamp) - Submit logs in chronological order when possible
- Account for timezone differences (submit in UTC)
Data Validation
Validate data before submission:
- Ensure all required fields are present
- Verify timestamp formats (integer, not string)
- Check that IP addresses are valid
- Confirm status codes are valid HTTP codes
- Validate field types match specification
Monitoring
Monitor API integration health:
- Track submission success rate
- Monitor rate limit consumption
- Alert on sustained errors
- Log API response times
- Track batch processing efficiency
Integration Examples
Nginx Log Shipping
Ship Nginx logs to AtomicEdge:
log_format waf_json escape=json
'{'
'"timestamp_ms":$msec,'
'"host":"$host",'
'"client_ip":"$remote_addr",'
'"uri":"$request_uri",'
'"method":"$request_method",'
'"status":$status,'
'"bytes_sent":$bytes_sent,'
'"user_agent":"$http_user_agent"'
'}';
access_log /var/log/nginx/access.json waf_json;
Then use a log shipper to submit to the API.
Vector Configuration
Use Vector to collect and forward logs:
[sources.nginx_access]
type = "file"
include = ["/var/log/nginx/access.json"]
read_from = "beginning"
[transforms.parse_json]
type = "remap"
inputs = ["nginx_access"]
source = '''
. = parse_json!(.message)
'''
[sinks.atomicedge]
type = "http"
inputs = ["parse_json"]
uri = "https://api.atomicedge.io/api/vector/access"
encoding.codec = "json"
batch.max_events = 100
batch.timeout_secs = 5
[sinks.atomicedge.request.headers]
Authorization = "Bearer YOUR_TOKEN"
Content-Type = "application/json"
Python Script
Simple Python script for log submission:
import requests
import json
import time
class AtomicEdgeLogger:
def __init__(self, token):
self.token = token
self.base_url = "https://api.atomicedge.io/api/vector"
self.headers = {
"Authorization": f"Bearer {token}",
"Content-Type": "application/json"
}
def submit_waf_logs(self, logs):
"""Submit WAF security logs"""
url = f"{self.base_url}/waf"
response = requests.post(url, json=logs, headers=self.headers)
response.raise_for_status()
return response.json()
def submit_access_logs(self, logs):
"""Submit access logs"""
url = f"{self.base_url}/access"
response = requests.post(url, json=logs, headers=self.headers)
response.raise_for_status()
return response.json()
# Usage
logger = AtomicEdgeLogger("YOUR_TOKEN")
waf_log = {
"timestamp_ms": int(time.time() * 1000),
"host": "example.com",
"client_ip": "203.0.113.45",
"uri": "/admin.php",
"method": "GET",
"waf_file": "/etc/caddy/rules/attack.conf",
"rule_id": "920100",
"severity": "CRITICAL",
"msg": "Attack detected"
}
result = logger.submit_waf_logs([waf_log])
print(f"Submitted: {result['processed']} logs")
Shell Script
Simple shell script using curl:
#!/bin/bash
API_TOKEN="YOUR_TOKEN"
API_URL="https://api.atomicedge.io/api/vector/access"
# Create log entry
LOG_ENTRY=$(cat <<EOF
{
"timestamp": $(date +%s),
"host": "example.com",
"client_ip": "203.0.113.45",
"uri": "/index.html",
"method": "GET",
"status": 200,
"bytes_sent": 4096,
"user_agent": "curl/7.68.0"
}
EOF
)
# Submit to API
curl -X POST "$API_URL" \
-H "Authorization: Bearer $API_TOKEN" \
-H "Content-Type: application/json" \
-d "$LOG_ENTRY"
Troubleshooting
Authentication Failures
If receiving 401 Unauthorized:
- Verify token is correctly copied
- Check for extra whitespace in token
- Ensure Authorization header format:
Bearer TOKEN - Confirm token has not been revoked
- Verify API access is enabled for your account
Invalid Request Format
If receiving 400 Bad Request:
- Validate JSON syntax
- Check all required fields are present
- Verify field types (integers for timestamps, not strings)
- Ensure timestamp is in correct format (ms for WAF, seconds for access)
- Review error message for specific field issues
Partial Processing
If receiving 207 Multi-Status:
- Review errors array for specific failures
- Check indices to identify problematic entries
- Fix validation issues in failed entries
- Do not resubmit successfully processed entries
- Implement validation before submission
Rate Limiting
If receiving 429 Too Many Requests:
- Reduce request frequency
- Increase batch size to reduce request count
- Implement exponential backoff
- Check X-RateLimit-Reset header for reset time
- Consider multiple API tokens for high-volume scenarios
Connection Issues
If experiencing timeouts or connection errors:
- Verify API endpoint URL is correct
- Check network connectivity
- Ensure firewall allows outbound HTTPS
- Test with curl to isolate client issues
- Check for proxy configuration requirements
Test connectivity:
curl -v https://api.atomicedge.io/api/vector/waf \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '[]'
Expected response: 200 OK with “Processed 0 log entries”
