API reference
Ingest logs by sending a POST request to the ingestion endpoint with a Bearer API key. Current API version: v1 (path versioning).
Endpoints
1. Batch Ingestion (POST /v1/logs)
Used by the SDK to send multiple logs in a single request. Max 100 events.
{
"events": [
{
"message": "User signed in",
"level": "info",
"metadata": { "userId": 123 }
},
{
"message": "Payment failed",
"level": "error",
"metadata": { "orderId": "abc", "amount": 50 }
}
]
}2. Single Event Ingestion (POST /v1/ingest)
Perfect for manual HTTP requests or simple scripts where you don't want to wrap logs in an array.
{
"message": "Server started",
"level": "info",
"metadata": { "region": "us-east-1" }
}Examples (SDK-less)
cURL
curl -X POST https://logger-api-dxqb.onrender.com/v1/ingest \
-H "Authorization: Bearer <your_api_key>" \
-H "Content-Type: application/json" \
-d '{
"message": "Testing from curl",
"level": "info",
"metadata": { "tag": "test" }
}'JavaScript (Fetch API)
fetch('https://logger-api-dxqb.onrender.com/v1/ingest', {
method: 'POST',
headers: {
'Authorization': 'Bearer <your_api_key>',
'Content-Type': 'application/json'
},
body: JSON.stringify({
message: 'Logging from fetch',
level: 'warn',
metadata: { browser: 'Chrome' }
})
});Python (Requests)
import requests
url = "https://logger-api-dxqb.onrender.com/v1/ingest"
headers = {
"Authorization": "Bearer <your_api_key>",
"Content-Type": "application/json"
}
data = {
"message": "Hello from Python",
"level": "info",
"metadata": {"source": "script"}
}
response = requests.post(url, json=data, headers=headers)Headers
- Authorization:
Bearer <api_key>(required) - Content-Type:
application/json - Idempotency-Key: (optional) Unique value for critical logs to avoid duplicates on retry
- X-Request-Id: (optional) Request ID for tracing
Field Reference
Fields: message (required); level (debug | info | warn | error); timestamp (ISO 8601); metadata, env, source (optional).
Dynamic Metadata & Errors
The metadata field accepts any valid JSON object. This is ideal for logging "unknown" data like mobile device info, app state, or complex server errors.
Tip: Formatting Errors
In many languages, JSON.stringify(error) returns an empty object {}. To log errors correctly via the Direct Ingestion API, you should manually extract the properties you care about.
const logError = (err) => {
return fetch('https://logger-api-dxqb.onrender.com/v1/ingest', {
method: 'POST',
headers: { 'Authorization': 'Bearer <key>', 'Content-Type': 'application/json' },
body: JSON.stringify({
message: err.message,
level: 'error',
metadata: {
name: err.name,
stack: err.stack, // capture the stack trace
code: err.code // if available
}
})
});
};Flexible Schemas
You don't need to define fields in advance. Just send whatever context helps you debug.
{
"message": "User checkout failed",
"metadata": {
"cart": { "items": ["sku_1", "sku_2"], "total": 45.99 },
"device": { "os": "Android", "version": "14" },
"experiment_group": "variant_b"
}
}Responses
- 202 Accepted – Body:
{ "accepted": N }(N = number of events accepted) - 400 Bad Request – Invalid JSON, missing
events, or more than 100 events - 401 Unauthorized – Missing or invalid API key
- 403 Forbidden – API key revoked or disabled
- 429 Too Many Requests – Rate limit exceeded;
Retry-Afterheader may be set - 503 Service Unavailable – Queue full; retry later
Rate limit
Per API key; when exceeded the API returns 429. Use the Retry-After response header when present. Back off and do not retry in a tight loop. The SDK throws an error with message "Too many requests; retry after X seconds" when 429 is received (X from Retry-After), so your app can catch and display it.
Quotas
Free tier: 10,000 logs per month per project, 7-day retention. If you need a higher limit, use the dashboard or contact support.
Validation and error responses
API errors return JSON with error and optional message: { "error": "Bad Request", "message": "description" }. Always validate on the server; client-side checks are for UX only.
- Ingestion (POST /v1/logs):
messagerequired per event;levelone of debug | info | warn | error;eventsarray max 100. - Auth (signup / login):
emailandpasswordrequired; password minimum 8 characters. Signup returns 409 if email already registered. - Profile (PATCH /api/dashboard/me): At least one field required. Returns 409 with message "Username already taken." if
usernameis taken. - Destination (PATCH project destination): When
typeiswebhook,webhook_urlrequired; whenlogger,read_api_urlrequired; whendirect_db_*,direct_db_urlrequired.
Testing with the SDK or test-backend
The @logship/logger SDK and the examples/test-backend app both send requests in this format. Use them to verify your API key and see logs in the dashboard. See Getting started and SDK reference.