Sending logs using the Structured JSON endpoint (Structured JSON Logs)
The Structured JSON Logs endpoint (/ingest/json) accepts standard JSON –
either a single JSON object or a JSON array of objects. This endpoint is designed for
structured log data where each event is a JSON object.
If you are using bearer token authentication, complete the setup steps in Setting up bearer token authentication before proceeding.
Request format
Only application/json is accepted as the Content-Type.
Single JSON object:
{"timestamp":1771007942000,"message":"single event","level":"INFO"}
JSON array of objects:
[ {"timestamp":1771007942000,"message":"event one","level":"INFO"}, {"timestamp":1771007943000,"message":"event two","level":"ERROR"} ]
Accepted JSON value types
This endpoint is strict – only JSON objects are accepted as events.
| Input | Behavior |
|---|---|
| Single JSON object | Accepted as one event |
| JSON array of objects | Each object becomes a separate event |
Empty array [] |
Accepted, produces 0 events |
| Non-object in array (string, number, etc.) | Skipped |
Top-level primitive ("hello", 42) |
Skipped |
Concatenated objects {...}{...} |
Only first object parsed |
Example – array with mixed types:
[ {"timestamp":1771007942000,"message":"valid object"}, "just a string", 42, {"timestamp":1771007943000,"message":"another valid object"} ]
Result: 2 events ingested (the objects), 2 skipped (the string and number).
Timestamp field
The "timestamp" field is in epoch milliseconds, same as the NDJSON endpoint.
| Format | Example | Interpreted as |
|---|---|---|
| Numeric (millis) | "timestamp":1771007942000 |
1771007942000 ms |
| Missing | (no timestamp field) | Server current time |
| Non-numeric | "timestamp":"invalid" |
Server current time |
Example request
curl -X POST "https://logs.<region>.amazonaws.com/ingest/json?logGroup=MyLogGroup&logStream=MyStream" \ -H "Authorization: Bearer ACWL<token>" \ -H "Content-Type: application/json" \ -d '[{"timestamp":1771007942000,"message":"User logged in","user_id":"u-123"},{"timestamp":1771007943000,"message":"Order placed","order_id":"o-456"}]'
Responses
Success (all events accepted):
HTTP 200 OK {}
Partial success (some events rejected):
{ "partialSuccess": { "rejectedLogRecords": 5, "errorMessage": "{\"tooOldLogEventCount\": 3, \"tooNewLogEventCount\": 1, \"expiredLogEventCount\": 1}" } }
The rejectedLogRecords field is the total number of rejected events. The errorMessage field contains a JSON-encoded breakdown by rejection reason:
tooOldLogEventCount– Events with timestamps older than the retention periodtooNewLogEventCount– Events with timestamps too far in the futureexpiredLogEventCount– Events that expired during processing
Best practices
Batching events
For better performance and efficiency:
Batch multiple events in a single request when possible
Recommended batch size: 10–100 events per request
Maximum request size: 1 MB
Error handling
Implement proper error handling in your application. Common HTTP status codes:
200 OK– Logs successfully ingested400 Bad Request– Invalid request format or parameters401 Unauthorized– Invalid or expired bearer token403 Forbidden– Insufficient permissions404 Not Found– Log group or stream doesn't exist429 Too Many Requests– Rate limit exceeded500 Internal Server Error– Service error (retry with exponential backoff)
Limitations
Maximum event size: 256 KB per event
Maximum request size: 1 MB
Maximum events per request: 10,000
Log group names must follow CloudWatch Logs naming conventions
Bearer token authentication must be enabled on the log group if bearer token authentication is used.