cancel
Showing results for 
Search instead for 
Did you mean: 
KyleYoung
Employee
Employee

Ever been mid-incident, staring at a dashboard, wishing you could just grab the last hour of logs for a specific environment without opening a ticket or waiting on someone? That's exactly what the v2 Log API is built for. 

It's a lightweight, read-only HTTP endpoint that returns log records for the PaaS environments your account is licensed for. Point a GET request at it, describe what you want — environment, service, time range, an optional search term — and get back a clean JSON envelope of matching records. It's designed for the real world: dashboards, incident-response tooling, and the quick ad-hoc scripts you reach for when something looks off. 

In this post I'll walk you through how it works end to end — authentication, every parameter, the response shape, error handling, and a few copy-paste examples to get you moving. 

Migrating from v1? If you already have a v1 client, read the Log API — Migration Guide (v1 → v2) instead — it covers the move step by step. 

The 30-second overview 

You issue an HTTP GET with query parameters, and you receive a JSON envelope containing matching log records. That's the whole model. 

A couple of things worth knowing up front: 

  • The API is read-only — you're never changing anything, just retrieving. 
  • Each response is capped at 1000 records. If you need more, narrow your time window and make multiple calls. 

Authentication: guard your key 

Every request carries your API key in the x-api-key header: 

x-api-key: <your-api-key> 

Your account team issues this key at onboarding. Treat it like a password — it grants read access to your log data. 

Rotate it on a schedule you agree with your account team, or immediately if you suspect it's leaked. When a rotation happens, you get a new key and your existing key keeps working for 7 days by default. (The migration guide's “Key rotations after migration” section has the finer details.) 

The endpoint 

There's just one: 

  • Path: /filter 
  • Method: GET 

So a full request URL looks like: 

https://log-api.alfrescocloud.com/v2/filter?<query-parameters> 

One endpoint, one method. Everything you do here is a variation on that. 

The query parameters, one by one 

There are seven parameters. Only one is required — the rest have sensible defaults. 

env — required 

The PaaS environment whose logs you want. It must be one of the environments licensed to your account (for example customer-devcustomer-uatcustomer-prod). Ask your account team for the exact env values that apply to you. 

  • Missing it → 400 env-required 
  • Not in your licensed set → 400 env-not-permitted 

service — optional (default acs) 

Selects which service's logs to return. Three fixed values: 

Value 

Returns logs from 

acs (default) 

The content service — the main Alfresco repository and its content-handling components. 

search 

The search service. 

transform 

The content-transform service. 

Anything else → 400 service-invalid. 

time_from — optional (default now - 1h) 

The lower bound of your time window. Three formats accepted: 

  • ISO-8601 — 2026-08-04T09:00:00Z 
  • Epoch milliseconds — 1754297400000 
  • Relative — nownow - 30mnow - 6hnow - 2d (units: m minutes, h hours, d days) 

Unparseable → 400 time-invalid. 

time_to — optional (default now) 

The upper bound of your window. Same three formats as time_from. 

sort — optional (default desc) 

Orders returned records by timestamp: 

  • desc — newest first (default) 
  • asc — oldest first 

Anything else → 400 sort-invalid. 

limit — optional (default 10, max 1000) 

Maximum number of records returned. Values above 1000 are clamped to 1000. A non-integer or a value ≤ 0 → 400 limit-invalid. 

search_string — optional (no default) 

Filters the response to records whose message body contains the given substring. It's a case-sensitive, plain-string match — not a regex. Max length 1024 characters. 

Remember to URL-encode the value if it contains characters like +&#, or spaces. Over 1024 characters → 400 search-string-too-long. 

What you get back 

Successful responses (200 OK) 

The body is a JSON envelope with a single top-level logs array. Each element is a log record: 

{ 

  "logs": [ 

    { 

      "timestamp": "2026-08-04T09:12:33.184Z", 

      "level": "INFO", 

      "message": "Request processed in 42ms", 

      "service": "acs-catalina" 

    } 

  ] 

} 

Every field is copied straight from the source record and is null when the source omits it — so treat all four as nullable: 

  • timestamp — RFC 3339 UTC; when the record was emitted at source. 
  • level — the log level as recorded at source (e.g. INFO, WARN, ERROR). 
  • message — the log message body. 
  • service — the specific component that emitted the record (e.g. acs-catalina, alfresco-insight-engine, transform-service). Note this is more granular than the request's service parameter — it names the individual component, not the service group. 

If nothing matches, logs comes back as []. 

Error responses 

Every documented error has the same shape: 

{ "error": "<stable-code>" } 

Those <stable-code> values are stable across releases — branch on them programmatically rather than parsing human-readable text. 

HTTP 

error code 

Meaning 

400 

env-required 

The env parameter is missing. 

400 

env-not-permitted 

Your API key isn't licensed for the requested env. 

400 

service-invalid 

The service value isn't acs / search / transform. 

400 

sort-invalid 

The sort value isn't asc or desc. 

400 

limit-invalid 

The limit value isn't a positive integer. 

400 

time-invalid 

time_from or time_to couldn't be parsed. 

400 

search-string-too-long 

search_string exceeds 1024 characters. 

401 

unauthorized 

The x-api-key header is missing, unknown, revoked, or its rotation grace period has expired. 

403 

not-found 

The path or method doesn't exist. GET /filter is the only supported request. 

429 

rate-limited 

You exceeded your per-customer rate limit. Back off and retry. 

429 

quota-exceeded 

You exhausted your quota for the current period. Retrying won't help until it resets. 

500 

internal-error 

Something unexpected happened. Report it with the request timestamp. 

502 

upstream-error / upstream-unreachable 

The backend log store errored or was unreachable. Transient — retry. 

504 

poll-budget-exceeded 

The query exceeded the ~20s server budget. Narrow the window or add a search_string. 

Two things that trip people up: 

  • A 403 never means your key was refused. Every auth failure comes back as 401 unauthorized. A 403 means your request didn't match GET /filter — check the path and method. 
  • Rarely, an infrastructure-level 500 or 502 returns a body that isn't an { "error": … } object. If a response carries no error field, treat it as a transient server error and retry. 

Rate limits 

 

Rate limiting applies where a rate-limit policy has been provisioned for your deployment. Where one is, your key is subject to a per-customer rate limit and a daily quota — both agreed with your account team at onboarding. Exceed either and you get 429 Too Many Requests, with the error code telling you which: 

  • { "error": "rate-limited" } — you're sending faster than your agreed rate. The allowance refills continuously, so back off and retry. 
  • { "error": "quota-exceeded" } — you've used your whole allowance for the period. Retrying keeps failing until it resets; stop and resume afterward. 

Where no policy is provisioned, neither 429 code is returned. Check with your account team if you're unsure which applies. 

There's no Retry-After header — use exponential backoff with jitter instead: start around one second, double on each failure, and cap at a ceiling that suits your workload. 

Examples to get you started 

  1. Recent ACS logs from the last hour (all defaults) 

GET https://log-api.alfrescocloud.com/v2/filter?env=customer-prod 

x-api-key: <your-api-key> 

Uses service=acstime_from=now - 1htime_to=nowsort=desclimit=10. 

  1. Search-service records in a specific window 

GET https://log-api.alfrescocloud.com/v2/filter?env=customer-prod&service=search 

    &time_from=2026-08-04T09:00:00Z&time_to=2026-08-04T10:00:00Z&limit=500 

x-api-key: <your-api-key> 

Up to 500 search-service records between 09:00 and 10:00 UTC on 2026-08-04. 

  1. Hunt for a specific error string in the last 6 hours 

GET https://log-api.alfrescocloud.com/v2/filter?env=customer-prod 

    &search_string=Timeout&limit=200&time_from=now%20-%206h 

x-api-key: <your-api-key> 

Up to 200 ACS records from the last 6 hours whose message contains Timeout. Note the URL-encoded spaces (%20) in time_from. 

  1. Oldest records first (chronological) 

GET https://log-api.alfrescocloud.com/v2/filter?env=customer-prod&sort=asc 

    &time_from=now%20-%202h&limit=1000 

x-api-key: <your-api-key> 

Up to 1000 ACS records from the last 2 hours, oldest first — handy when you're correlating a sequence of events. 

A few tips from experience 

  • Retry transient errors (502, 504) with exponential backoff, and treat 429 rate-limited the same way. Don't retry 400, 401, 403, or 429 quota-exceeded — the first three need a fix on your side, the last needs the quota to reset. 
  • Cache responses if you're polling the same window from multiple places. Every request costs a backend query. 
  • Narrow the time window rather than raising limit when you know roughly when an event happened. Time-scoped queries return faster and dodge the poll-budget timeout. 
  • Use search_string when you know a substring to filter on — it filters server-side, so your client isn't wading through records that don't match. 
  • Generate your client from the openapi.yaml (an OpenAPI 3.0.3 spec, version 2.0.0, attached to the Confluence page) rather than hand-writing request building and error handling. The error enum in the spec is the authoritative list of codes to branch on. Render it by importing the file into Swagger Editor via File → Import file. 
  • Never log the x-api-key value. Redact it before including any request URL in a support ticket, log line, or shared trace. 

Need a hand? 

Questions, unexpected errors, or a request for higher rate limits? Reach out to your account team or file a support ticket. Include the request timestamp, the full request URL (redact the API key), and the observed response so we can reproduce it quickly. 

Happy log-hunting — and let us know in the comments how you're wiring the Log API into your own tooling. 👇