# Logs

Error log and access log of a site.

## Error log

`GET /sites/{site_id}/logs/errors` · scope `logs:read`

Recent PHP and web server errors of THIS site (the Error log tab): last 7 days, grouped, sanitised (paths shown relative to the site folder, secrets hidden). php_hint=true when the errors look like code written for an older PHP version. Cached 60 s; 20 fetches per 10 minutes per account.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `site_id` | path | integer | yes | The site id (see GET /sites). |

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/sites/123/logs/errors" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/sites/123/logs/errors", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/logs/errors", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "entries": [
      {
        "level": "Fatal error",
        "message": "Uncaught Error: Call to undefined function mysql_connect() in /wp-content/plugins/old/db.php:12",
        "count": 3,
        "first": "2026-09-19T08:00:00",
        "last": "2026-09-19T09:30:00"
      }
    ],
    "total": 3,
    "partial": false,
    "lookback_days": 7,
    "php_version": "PHP 8.3",
    "php_hint": true,
    "fetched_at": "2026-09-20 09:00:00 UTC",
    "seconds": 1.8,
    "cached": false
  }
}
```

Errors: `conflict`, `not_found`, `rate_limited`, `scope_missing`, `unauthorized`

## Access log

`GET /sites/{site_id}/logs/access` · scope `logs:read`

Requests that reached the web server for this site's hostnames, newest last. The client IP is the visitor as the CDN reported it. 30 fetches per 10 minutes per account.

### Parameters

| Name | In | Type | Required | Description |
|---|---|---|---|---|
| `site_id` | path | integer | yes | The site id (see GET /sites). |
| `hours` | query | integer | no | How far back to look. Default: `1`. |
| `lines` | query | integer | no | At most this many (the newest) lines. Default: `200`. |

### Example

```bash
curl -s "https://app.pbn.ltd/api/v1/sites/123/logs/access?hours=1&lines=100" \
  -H "Authorization: Bearer $PBN_API_KEY"
```

```python
import os
import requests

headers = {"Authorization": "Bearer " + os.environ["PBN_API_KEY"]}
r = requests.get("https://app.pbn.ltd/api/v1/sites/123/logs/access?hours=1&lines=100", headers=headers, timeout=120)
print(r.status_code, r.json())
```

```javascript
const res = await fetch("https://app.pbn.ltd/api/v1/sites/123/logs/access?hours=1&lines=100", {
  method: "GET",
  headers: {Authorization: `Bearer ${process.env.PBN_API_KEY}`}
});
console.log(res.status, await res.json());
```

### Response

`200`

```json
{
  "data": {
    "entries": [
      {
        "time": "2026-09-20T08:59:58+00:00",
        "client_ip": "203.0.113.9",
        "host": "example.com",
        "method": "GET",
        "path": "/",
        "protocol": "HTTP/1.1",
        "status": 200,
        "bytes": 5123,
        "referer": null,
        "user_agent": "Mozilla/5.0 ...",
        "scheme": "https"
      }
    ],
    "count": 1,
    "status_counts": {
      "2xx": 1
    },
    "hours": 1,
    "partial": false,
    "note": "Requests the CDN answered from its cache never reach the server and are not in this log."
  }
}
```

Errors: `conflict`, `not_found`, `rate_limited`, `scope_missing`, `unauthorized`
