# Observability

### On-demand service logs

`GET /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/services/{name}/logs`

**Required role:** reader

**Parameters**

- `filter` _(query)_ · `string` · optional — Substring line filter.
- `limit` _(query)_ · `number` · optional — Max lines (≤1000, default 100).
- `end` _(query)_ · `string` · optional — Absolute window end (ISO). Only meaningful with start; defaults to now.
- `start` _(query)_ · `string` · optional — Absolute window start (ISO). Wins over since; capped to your plan’s retention.
- `since` _(query)_ · `string` · optional — Relative window, e.g. 1h (capped to your plan’s retention).
- `name` _(path)_ · `string` · required — Service name within the environment.
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Returns**

- `200` · `LogsResponseDto`

Attributes of `LogsResponseDto`:

- `serviceId` · `string` · read-only
- `lines` · `object[]` · read-only
- `truncated` · `boolean` · read-only
- `since` · `string <date-time>` · read-only — The RESOLVED absolute window start actually queried — after clamping the relative request to your plan’s retention. Honest: never the raw request string.

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/services/:name/logs \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "serviceId": "svc_01example0000000000000000x",
  "lines": [
    {
      "ts": "2026-01-01T00:00:00.000Z",
      "line": "example",
      "stream": "stdout",
      "location": "example",
      "container": "example"
    }
  ],
  "truncated": true,
  "since": "2026-01-01T00:00:00.000Z"
}
```

### Account-wide combined log stream

`GET /accounts/{accountId}/logs`

**Required role:** reader

One combined, newest-first log stream across every project/environment/service of the account, each line attributed to its owning service. Live tail: poll the same since-window on an interval and REPLACE your list with each response (the window is honest — see `since`).

**Parameters**

- `service` _(query)_ · `string` · optional — Scope to a service by name; spans environments when a project/environment is not also set.
- `environmentId` _(query)_ · `string` · optional — Scope to a single environment (must belong to projectId when both are given).
- `projectId` _(query)_ · `string` · optional — Scope the stream to a single project.
- `filter` _(query)_ · `string` · optional — Substring line filter.
- `limit` _(query)_ · `number` · optional — Max lines (≤1000, default 100).
- `end` _(query)_ · `string` · optional — Absolute window end (ISO). Only meaningful with start; defaults to now.
- `start` _(query)_ · `string` · optional — Absolute window start (ISO). Wins over since; capped to your plan’s retention.
- `since` _(query)_ · `string` · optional — Relative window, e.g. 1h (capped to your plan’s retention).
- `accountId` _(path)_ · `string` · required

**Returns**

- `200` · `AccountLogsResponseDto`

Attributes of `AccountLogsResponseDto`:

- `accountId` · `string` · read-only
- `lines` · `object[]` · read-only
- `truncated` · `boolean` · read-only — True when the line limit was hit before attribution — the RAW fetched count reached the limit (older lines were dropped). Computed BEFORE unattributable lines are filtered, so it never under-reports.
- `since` · `string <date-time>` · read-only — The RESOLVED absolute window start actually queried — after clamping the relative request to your plan’s retention. Honest: never the raw request string.

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/logs \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "accountId": "acct_01example0000000000000000x",
  "lines": [
    {
      "ts": "2026-01-01T00:00:00.000Z",
      "line": "example",
      "project": "example",
      "environment": "example",
      "service": "example",
      "projectId": "project_01example0000000000000000x",
      "environmentId": "environment_01example0000000000000000x",
      "stream": "stdout",
      "replica": "example",
      "location": "example",
      "container": "example"
    }
  ],
  "truncated": true,
  "since": "2026-01-01T00:00:00.000Z"
}
```

### On-demand service metrics

`GET /accounts/{accountId}/projects/{projectId}/environments/{environmentId}/services/{name}/metrics`

**Required role:** reader

**Parameters**

- `range` _(query)_ · `string` · optional — Relative window, e.g. 1h (capped to your plan’s retention).
- `metric` _(query)_ · `"cpu" | "mem" | "req" | "latency"` · required
- `name` _(path)_ · `string` · required — Service name within the environment.
- `environmentId` _(path)_ · `string` · required
- `projectId` _(path)_ · `string` · required
- `accountId` _(path)_ · `string` · required

**Returns**

- `200` · `MetricsResponseDto`

Attributes of `MetricsResponseDto`:

- `serviceId` · `string` · read-only
- `metric` · `"cpu" | "mem" | "req" | "latency"` · read-only
- `unit` · `string` · read-only
- `range` · `object` · read-only — The RESOLVED absolute window actually queried — after clamping the relative request to your plan’s retention.
- `stepSec` · `number` · read-only
- `series` · `object[]` · read-only

**Example request**

```bash
curl https://api.koo.io/accounts/:accountId/projects/:projectId/environments/:environmentId/services/:name/metrics?metric=example \
  -H "Authorization: Bearer kc_your_api_token"
```

**Example response** (`200`)

```json
{
  "serviceId": "svc_01example0000000000000000x",
  "metric": "cpu",
  "unit": "example",
  "range": {
    "start": "2026-01-01T00:00:00.000Z",
    "end": "2026-01-01T00:00:00.000Z"
  },
  "stepSec": 1,
  "series": [
    {
      "labels": {
        "key": "example"
      },
      "points": [
        {
          "t": "2026-01-01T00:00:00.000Z",
          "v": 1
        }
      ]
    }
  ]
}
```
