---
title: "Monitoring Management API"
description: "Silly Development API reference for monitoring: manage projects and keys, and read issues, events and usage from code with a panel API key."
url: "https://sillydev.co.uk/docs/monitoring/api"
updated: "2026-10-14"
---

API reference

# Management API

Part of the panel API at /docs/panel, with a panel API key (\`sdevc\_\`) given the monitoring scopes. Monitoring keys cannot use it.

[← Monitoring docs](https://sillydev.co.uk/docs/monitoring) · 14 endpoints · Updated 14 October 2026

**Browse the docs**

## Monitoring

Application monitoring: the errors, metrics, events and slow operations your code sends with the SillyDev SDKs (`from sillydev import monitoring` in Python, `sillydev/monitoring` in JavaScript). Here you manage projects and their keys and read what was collected. Only available while monitoring is switched on; otherwise every endpoint here returns 404. Reading needs the `monitoring.read` scope and changing anything `monitoring.write`. Neither is part of a key's default scopes: give them to a key in the panel.

Projects belong to the account, not to a server, and nothing is collected until you make a key and call `init()` with it.

### List monitoring projects

GET`/monitoring/projects`

Account scope monitoring.read

Lists the account's monitoring projects, each with the limits that apply to it now. `meta` says what the account may still do. An account's limits follow its plan by themselves; while any server it owns has a paid plan, every project gets the paid limits. Returns 404 while monitoring is switched off.

Example

```
curl "https://sillydev.co.uk/panel/api/client/monitoring/projects" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200The projects.

```
{
    "object": "list",
    "data": [
        {
            "object": "monitoring_project",
            "attributes": {
                "uuid": "5f0c8a52-3e1b-4b8e-9d1f-6a2c7e4b9a10",
                "name": "orders-bot",
                "node": {
                    "number": 1,
                    "public_url": "https://ingest1.sillydev.co.uk"
                },
                "allowed_origins": [
                    "https://example.com"
                ],
                "tier": "free",
                "disabled": false,
                "limits": {
                    "series": 40,
                    "errors_per_day": 5000,
                    "events_per_day": 10000,
                    "slow_per_day": 2000,
                    "requests_per_minute": 60,
                    "browser_requests_per_minute": 120,
                    "retention_minute_days": 2,
                    "retention_hour_days": 90,
                    "retention_day_days": 400,
                    "retention_occurrence_days": 30,
                    "retention_event_days": 14
                },
                "keys_limit": 5,
                "alerts": {
                    "new_issue": true,
                    "regression": true,
                    "error_spike": null,
                    "heartbeat_minutes": 10
                },
                "servers": [
                    {
                        "uuid": "8f4b1c2d-7a6e-4f3b-9c1d-2e5a6b7c8d90",
                        "identifier": "8f4b1c2d",
                        "name": "My bot"
                    }
                ],
                "keys_count": 2,
                "created_at": "2026-10-13T22:00:00+00:00"
            }
        }
    ],
    "meta": {
        "tier": "free",
        "project_limit": 2,
        "can_create": true,
        "email_verified": true
    }
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| datarequired | array of object |  |
| data\[\].objectrequired | string |  |
| data\[\].attributesrequired | object |  |
| data\[\].attributes.uuidrequired | string (uuid) |  |
| data\[\].attributes.namerequired | string |  |
| data\[\].attributes.noderequired | object | Where the project's data is sent. The SDKs work this out from the key. |
| data\[\].attributes.node.number | integer |  |
| data\[\].attributes.node.public_url | string (uri) |  |
| data\[\].attributes.allowed_originsrequired | array of string | Websites browser keys work from. |
| data\[\].attributes.tierrequired | one of 'free', 'paid' | `paid` while any server the account owns has a paid plan. |
| data\[\].attributes.disabledrequired | boolean | Switched off by an administrator. Data sent to a disabled project is refused. |
| data\[\].attributes.limitsrequired | object | What the project may send and how long it is kept. A day is the UTC day. |
| data\[\].attributes.limits.series | integer | Metric series (a name plus a set of tag values) the project may have. Data for new series beyond this is dropped. |
| data\[\].attributes.limits.errors_per_day | integer |  |
| data\[\].attributes.limits.events_per_day | integer |  |
| data\[\].attributes.limits.slow_per_day | integer | Slow operations recorded per day. |
| data\[\].attributes.limits.requests_per_minute | integer | Requests per minute from server keys. |
| data\[\].attributes.limits.browser_requests_per_minute | integer | Requests per minute from browser keys. |
| data\[\].attributes.limits.retention_minute_days | integer | Days metrics are kept at one-minute resolution. |
| data\[\].attributes.limits.retention_hour_days | integer | Days metrics are kept at one-hour resolution. |
| data\[\].attributes.limits.retention_day_days | integer | Days metrics are kept at one-day resolution. |
| data\[\].attributes.limits.retention_occurrence_days | integer | Days each error occurrence is kept. Issues themselves are kept. |
| data\[\].attributes.limits.retention_event_days | integer |  |
| data\[\].attributes.keys_limitrequired | integer | How many keys you may make for the project. |
| data\[\].attributes.alertsrequired | object |  |
| data\[\].attributes.alerts.new_issue | boolean | Email when an error happens that has not been seen before. |
| data\[\].attributes.alerts.regression | boolean | Email when a resolved issue happens again. |
| data\[\].attributes.alerts.error_spike | integer \| null | Email when at least this many errors happen in five minutes. |
| data\[\].attributes.alerts.heartbeat_minutes | integer \| null | Email when no heartbeat has arrived for this many minutes, and again when one does. |
| data\[\].attributes.serversrequired | array of object | Servers linked to the project in the panel. |
| data\[\].attributes.keys_countrequired | integer |  |
| data\[\].attributes.created_atrequired | string (date-time) |  |
| metarequired | object |  |
| meta.tier | one of 'free', 'paid' |  |
| meta.project_limit | integer | How many projects the account may have now. |
| meta.can_create | boolean | Whether `createMonitoringProject` would succeed now. |
| meta.email_verified | boolean |  |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.

### Create a monitoring project

POST`/monitoring/projects`

Account scope monitoring.write Limited to 5 per minute

Creates a project and returns it. Nothing is collected until you create a key (`createMonitoringKey`) and call `init()` in your code with it.

The account's email address must be confirmed (403 otherwise), and an account may have a limited number of projects, more while it has a paid server: over the limit answers 400. Returns 404 while monitoring is switched off.

Body

| Name | Type | Description |
| --- | --- | --- |
| namerequired | string |  |

Example

```
curl -X POST "https://sillydev.co.uk/panel/api/client/monitoring/projects" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"orders-bot"}'
```

Response 201The new project.

```
{
    "object": "monitoring_project",
    "attributes": {
        "uuid": "5f0c8a52-3e1b-4b8e-9d1f-6a2c7e4b9a10",
        "name": "orders-bot",
        "node": {
            "number": 1,
            "public_url": "https://ingest1.sillydev.co.uk"
        },
        "allowed_origins": [],
        "tier": "free",
        "disabled": false,
        "limits": {
            "series": 40,
            "errors_per_day": 5000,
            "events_per_day": 10000,
            "slow_per_day": 2000,
            "requests_per_minute": 60,
            "browser_requests_per_minute": 120,
            "retention_minute_days": 2,
            "retention_hour_days": 90,
            "retention_day_days": 400,
            "retention_occurrence_days": 30,
            "retention_event_days": 14
        },
        "keys_limit": 5,
        "alerts": {
            "new_issue": true,
            "regression": true,
            "error_spike": null,
            "heartbeat_minutes": null
        },
        "servers": [],
        "keys_count": 0,
        "created_at": "2026-10-13T22:00:00+00:00"
    }
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| attributesrequired | object |  |
| attributes.uuidrequired | string (uuid) |  |
| attributes.namerequired | string |  |
| attributes.noderequired | object | Where the project's data is sent. The SDKs work this out from the key. |
| attributes.node.number | integer |  |
| attributes.node.public_url | string (uri) |  |
| attributes.allowed_originsrequired | array of string | Websites browser keys work from. |
| attributes.tierrequired | one of 'free', 'paid' | `paid` while any server the account owns has a paid plan. |
| attributes.disabledrequired | boolean | Switched off by an administrator. Data sent to a disabled project is refused. |
| attributes.limitsrequired | object | What the project may send and how long it is kept. A day is the UTC day. |
| attributes.limits.series | integer | Metric series (a name plus a set of tag values) the project may have. Data for new series beyond this is dropped. |
| attributes.limits.errors_per_day | integer |  |
| attributes.limits.events_per_day | integer |  |
| attributes.limits.slow_per_day | integer | Slow operations recorded per day. |
| attributes.limits.requests_per_minute | integer | Requests per minute from server keys. |
| attributes.limits.browser_requests_per_minute | integer | Requests per minute from browser keys. |
| attributes.limits.retention_minute_days | integer | Days metrics are kept at one-minute resolution. |
| attributes.limits.retention_hour_days | integer | Days metrics are kept at one-hour resolution. |
| attributes.limits.retention_day_days | integer | Days metrics are kept at one-day resolution. |
| attributes.limits.retention_occurrence_days | integer | Days each error occurrence is kept. Issues themselves are kept. |
| attributes.limits.retention_event_days | integer |  |
| attributes.keys_limitrequired | integer | How many keys you may make for the project. |
| attributes.alertsrequired | object |  |
| attributes.alerts.new_issue | boolean | Email when an error happens that has not been seen before. |
| attributes.alerts.regression | boolean | Email when a resolved issue happens again. |
| attributes.alerts.error_spike | integer \| null | Email when at least this many errors happen in five minutes. |
| attributes.alerts.heartbeat_minutes | integer \| null | Email when no heartbeat has arrived for this many minutes, and again when one does. |
| attributes.serversrequired | array of object | Servers linked to the project in the panel. |
| attributes.servers\[\].uuidrequired | string (uuid) |  |
| attributes.servers\[\].identifierrequired | string | The server's 8-character identifier. |
| attributes.servers\[\].namerequired | string |  |
| attributes.keys_countrequired | integer |  |
| attributes.created_atrequired | string (date-time) |  |

Errors

- 400 The account already has as many projects as it may.
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key lacks the `monitoring.write` scope, or the account's email address is not confirmed yet.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 409 The resource is busy or in a state that does not allow this right now.
- 422 Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.
- 429 Too many requests. Wait for the number of seconds in the `Retry-After` header, then try again.
- 503 The monitoring service cannot be reached right now. Nothing is lost; try again in a few minutes.

### Get a monitoring project

GET`/monitoring/projects/{project}`

Account scope monitoring.read

Returns one of the account's projects. Somebody else's project is a 404, the same as one that does not exist.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |

Example

```
curl "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200The project.

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| attributesrequired | object |  |
| attributes.uuidrequired | string (uuid) |  |
| attributes.namerequired | string |  |
| attributes.noderequired | object | Where the project's data is sent. The SDKs work this out from the key. |
| attributes.node.number | integer |  |
| attributes.node.public_url | string (uri) |  |
| attributes.allowed_originsrequired | array of string | Websites browser keys work from. |
| attributes.tierrequired | one of 'free', 'paid' | `paid` while any server the account owns has a paid plan. |
| attributes.disabledrequired | boolean | Switched off by an administrator. Data sent to a disabled project is refused. |
| attributes.limitsrequired | object | What the project may send and how long it is kept. A day is the UTC day. |
| attributes.limits.series | integer | Metric series (a name plus a set of tag values) the project may have. Data for new series beyond this is dropped. |
| attributes.limits.errors_per_day | integer |  |
| attributes.limits.events_per_day | integer |  |
| attributes.limits.slow_per_day | integer | Slow operations recorded per day. |
| attributes.limits.requests_per_minute | integer | Requests per minute from server keys. |
| attributes.limits.browser_requests_per_minute | integer | Requests per minute from browser keys. |
| attributes.limits.retention_minute_days | integer | Days metrics are kept at one-minute resolution. |
| attributes.limits.retention_hour_days | integer | Days metrics are kept at one-hour resolution. |
| attributes.limits.retention_day_days | integer | Days metrics are kept at one-day resolution. |
| attributes.limits.retention_occurrence_days | integer | Days each error occurrence is kept. Issues themselves are kept. |
| attributes.limits.retention_event_days | integer |  |
| attributes.keys_limitrequired | integer | How many keys you may make for the project. |
| attributes.alertsrequired | object |  |
| attributes.alerts.new_issue | boolean | Email when an error happens that has not been seen before. |
| attributes.alerts.regression | boolean | Email when a resolved issue happens again. |
| attributes.alerts.error_spike | integer \| null | Email when at least this many errors happen in five minutes. |
| attributes.alerts.heartbeat_minutes | integer \| null | Email when no heartbeat has arrived for this many minutes, and again when one does. |
| attributes.serversrequired | array of object | Servers linked to the project in the panel. |
| attributes.servers\[\].uuidrequired | string (uuid) |  |
| attributes.servers\[\].identifierrequired | string | The server's 8-character identifier. |
| attributes.servers\[\].namerequired | string |  |
| attributes.keys_countrequired | integer |  |
| attributes.created_atrequired | string (date-time) |  |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.

### Update a monitoring project

PATCH`/monitoring/projects/{project}`

Account scope monitoring.write Limited to 30 per minute

Changes the project's name, the websites its browser keys work from, and its alert emails. Only the fields you send change; within `alerts`, only the alerts you send.

`allowed_origins` replaces the whole list. Each entry is an origin as a browser sends it, a scheme and host with an optional port and no path, e.g. `https://example.com`. Browser data from anywhere else is refused.

Alerts are emailed to the account. `error_spike` is a number of errors in five minutes and `heartbeat_minutes` how long without a heartbeat counts as stopped; null switches either off. Each kind of alert is emailed at most once every half hour per project, and a stopped heartbeat once, then once more when it comes back.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |

Body

| Name | Type | Description |
| --- | --- | --- |
| name | string |  |
| allowed_origins | array of string |  |
| alerts | object |  |
| alerts.new_issue | boolean |  |
| alerts.regression | boolean |  |
| alerts.error_spike | integer \| null |  |
| alerts.heartbeat_minutes | integer \| null |  |

Example

```
curl -X PATCH "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"allowed_origins":["https://example.com"],"alerts":{"heartbeat_minutes":10}}'
```

Response 200The project as it is now.

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| attributesrequired | object |  |
| attributes.uuidrequired | string (uuid) |  |
| attributes.namerequired | string |  |
| attributes.noderequired | object | Where the project's data is sent. The SDKs work this out from the key. |
| attributes.node.number | integer |  |
| attributes.node.public_url | string (uri) |  |
| attributes.allowed_originsrequired | array of string | Websites browser keys work from. |
| attributes.tierrequired | one of 'free', 'paid' | `paid` while any server the account owns has a paid plan. |
| attributes.disabledrequired | boolean | Switched off by an administrator. Data sent to a disabled project is refused. |
| attributes.limitsrequired | object | What the project may send and how long it is kept. A day is the UTC day. |
| attributes.limits.series | integer | Metric series (a name plus a set of tag values) the project may have. Data for new series beyond this is dropped. |
| attributes.limits.errors_per_day | integer |  |
| attributes.limits.events_per_day | integer |  |
| attributes.limits.slow_per_day | integer | Slow operations recorded per day. |
| attributes.limits.requests_per_minute | integer | Requests per minute from server keys. |
| attributes.limits.browser_requests_per_minute | integer | Requests per minute from browser keys. |
| attributes.limits.retention_minute_days | integer | Days metrics are kept at one-minute resolution. |
| attributes.limits.retention_hour_days | integer | Days metrics are kept at one-hour resolution. |
| attributes.limits.retention_day_days | integer | Days metrics are kept at one-day resolution. |
| attributes.limits.retention_occurrence_days | integer | Days each error occurrence is kept. Issues themselves are kept. |
| attributes.limits.retention_event_days | integer |  |
| attributes.keys_limitrequired | integer | How many keys you may make for the project. |
| attributes.alertsrequired | object |  |
| attributes.alerts.new_issue | boolean | Email when an error happens that has not been seen before. |
| attributes.alerts.regression | boolean | Email when a resolved issue happens again. |
| attributes.alerts.error_spike | integer \| null | Email when at least this many errors happen in five minutes. |
| attributes.alerts.heartbeat_minutes | integer \| null | Email when no heartbeat has arrived for this many minutes, and again when one does. |
| attributes.serversrequired | array of object | Servers linked to the project in the panel. |
| attributes.servers\[\].uuidrequired | string (uuid) |  |
| attributes.servers\[\].identifierrequired | string | The server's 8-character identifier. |
| attributes.servers\[\].namerequired | string |  |
| attributes.keys_countrequired | integer |  |
| attributes.created_atrequired | string (date-time) |  |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 422 Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.
- 429 Too many requests. Wait for the number of seconds in the `Retry-After` header, then try again.

### Delete a monitoring project

DELETE`/monitoring/projects/{project}`

Account scope monitoring.write

Deletes the project and its keys at once, and all of its data (metrics, issues, events, slow operations) shortly after. Linked servers are unlinked and lose their key from their next start. This cannot be undone.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |

Example

```
curl -X DELETE "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 204Done. There is no response body.

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.

### List a project's keys

GET`/monitoring/projects/{project}/keys`

Account scope monitoring.read

Lists the project's keys without their secrets, which are only shown when a key is made. `hint` is a key's last four characters. Keys the panel made for linked servers are listed too, with `server` set.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |

Example

```
curl "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/keys" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200The keys.

```
{
    "object": "list",
    "data": [
        {
            "object": "monitoring_key",
            "attributes": {
                "id": 7,
                "name": "Production",
                "kind": "server",
                "hint": "x9Qa",
                "server": null,
                "created_at": "2026-10-13T22:05:00+00:00"
            }
        }
    ]
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| datarequired | array of object |  |
| data\[\].objectrequired | string |  |
| data\[\].attributesrequired | object |  |
| data\[\].attributes.idrequired | integer |  |
| data\[\].attributes.namerequired | string |  |
| data\[\].attributes.kindrequired | one of 'server', 'browser' |  |
| data\[\].attributes.hintrequired | string | The key's last four characters. |
| data\[\].attributes.serverrequired | any | The linked server this key was made for, or null for a key you made. |
| data\[\].attributes.created_atrequired | string (date-time) |  |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.

### Create a key

POST`/monitoring/projects/{project}/keys`

Account scope monitoring.write Limited to 10 per minute

Makes a key and returns its secret in `meta.secret_key`, once: it cannot be shown again. A `server` key (`sdevm_...`) is for your application's backend and must be kept secret. A `browser` key (`sdevb_...`) is for a web page; it can only send data, and only from the project's `allowed_origins`.

The number after the prefix is the project's ingest node, so the SDKs work out where to send data from the key alone. A project may have a limited number of keys (`keys_limit` on the project); the keys made for linked servers do not count.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |

Body

| Name | Type | Description |
| --- | --- | --- |
| namerequired | string |  |
| kindrequired | one of 'server', 'browser' |  |

Example

```
curl -X POST "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/keys" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"Production","kind":"server"}'
```

Response 201The new key, with its secret in \`meta\`.

```
{
    "object": "monitoring_key",
    "attributes": {
        "id": 7,
        "name": "Production",
        "kind": "server",
        "hint": "x9Qa",
        "server": null,
        "created_at": "2026-10-13T22:05:00+00:00"
    },
    "meta": {
        "secret_key": "sdevm_1_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx9Qa"
    }
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| objectrequired | string |  |
| attributesrequired | object |  |
| attributes.idrequired | integer |  |
| attributes.namerequired | string |  |
| attributes.kindrequired | one of 'server', 'browser' |  |
| attributes.hintrequired | string | The key's last four characters. |
| attributes.serverrequired | any | The linked server this key was made for, or null for a key you made. |
| attributes.created_atrequired | string (date-time) |  |
| metarequired | object |  |
| meta.secret_keyrequired | string | The whole key. Shown this once. |

Errors

- 400 The project already has as many keys as it may.
- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 422 Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.
- 429 Too many requests. Wait for the number of seconds in the `Retry-After` header, then try again.

### Delete a key

DELETE`/monitoring/projects/{project}/keys/{key}`

Account scope monitoring.write

Deletes the key. Data sent with it is refused within moments. Deleting the key of a linked server unlinks that server.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |
| keyrequired | integer | The key's numeric `id`. |

Example

```
curl -X DELETE "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/keys/{key}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 204Done. There is no response body.

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.

### List issues

GET`/monitoring/projects/{project}/issues`

Account scope monitoring.read

Lists the project's issues: errors grouped by where they happened, newest first by default. This and the other data endpoints answer with the monitoring service's JSON as it is, without the `object`/`attributes` envelope, and their times are Unix seconds.

Returns 503 `MonitoringUnavailable` while the monitoring service cannot be reached; your data is not lost, as the SDKs keep it until it can be sent.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |
| status | one of 'unresolved', 'resolved', 'ignored', 'all' | Which issues to list. |
| environment | string | Only issues seen in this environment. |
| release | string | Only issues seen in this release. |
| q | string | Searches the issues' type and title. |
| sort | one of 'last_seen', 'first_seen', 'count' | The order of the list. |
| page | integer | The page of results to return, starting at 1. |
| per_page | integer | How many issues to return on each page. |

Example

```
curl "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/issues" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200A page of issues.

```
{
    "data": [
        {
            "fingerprint": "3f1a9c0e5b7d2a4c",
            "type": "KeyError",
            "title": "'user_id'",
            "culprit": "on_order (bot/cogs/orders.py)",
            "status": "unresolved",
            "handled": false,
            "count": 1312,
            "count_24h": 41,
            "first_seen": 1760100000,
            "last_seen": 1760390405,
            "regressed_at": null,
            "first_release": "1.4.0",
            "last_release": "1.4.2",
            "environments": [
                "production"
            ],
            "services": [
                "orders-bot"
            ],
            "sparkline": [
                0,
                0,
                3,
                1,
                0,
                2,
                4,
                1,
                0,
                0,
                1,
                3,
                2,
                0,
                0,
                1,
                5,
                2,
                1,
                0,
                3,
                4,
                2,
                6
            ]
        }
    ],
    "pagination": {
        "total": 57,
        "page": 1,
        "per_page": 25
    }
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| data | array of object |  |
| data\[\].fingerprint | string |  |
| data\[\].type | string | The exception's type, e.g. `KeyError`. |
| data\[\].title | string | The first occurrence's message, at most 200 characters. |
| data\[\].culprit | string \| null | The innermost frame in your own code. |
| data\[\].status | one of 'unresolved', 'resolved', 'ignored' |  |
| data\[\].handled | boolean | Whether the latest occurrence was caught by your code. |
| data\[\].count | integer |  |
| data\[\].count_24h | integer |  |
| data\[\].first_seen | integer | Unix seconds. |
| data\[\].last_seen | integer | Unix seconds. |
| data\[\].regressed_at | integer \| null | When a resolved issue last came back, in Unix seconds. |
| data\[\].first_release | string \| null |  |
| data\[\].last_release | string \| null |  |
| data\[\].environments | array of string |  |
| data\[\].services | array of string |  |
| data\[\].sparkline | array of integer | Hourly counts for the last 24 hours, oldest first. |
| pagination | object |  |
| pagination.total | integer |  |
| pagination.page | integer |  |
| pagination.per_page | integer |  |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 422 Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.
- 503 The monitoring service cannot be reached right now. Nothing is lost; try again in a few minutes.

### Get an issue

GET`/monitoring/projects/{project}/issues/{fingerprint}`

Account scope monitoring.read

Returns one issue with its hourly counts for the last 14 days (`history`) and its latest occurrence (`latest`), including the stack trace.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |
| fingerprintrequired | string | The issue's `fingerprint`. |

Example

```
curl "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/issues/{fingerprint}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200The issue.

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| fingerprint | string |  |
| type | string | The exception's type, e.g. `KeyError`. |
| title | string | The first occurrence's message, at most 200 characters. |
| culprit | string \| null | The innermost frame in your own code. |
| status | one of 'unresolved', 'resolved', 'ignored' |  |
| handled | boolean | Whether the latest occurrence was caught by your code. |
| count | integer |  |
| count_24h | integer |  |
| first_seen | integer | Unix seconds. |
| last_seen | integer | Unix seconds. |
| regressed_at | integer \| null | When a resolved issue last came back, in Unix seconds. |
| first_release | string \| null |  |
| last_release | string \| null |  |
| environments | array of string |  |
| services | array of string |  |
| sparkline | array of integer | Hourly counts for the last 24 hours, oldest first. |
| history | array of array of integer | \[hour, count\] pairs for the last 14 days, hours in Unix seconds. |
| latest | object |  |
| latest.id | integer |  |
| latest.ts | integer | Unix seconds. |
| latest.type | string |  |
| latest.message | string |  |
| latest.handled | boolean |  |
| latest.stack | array of object | The stack frames, outermost first. |
| latest.cause | object \| null | The exception this one was raised from, in the same shape. |
| latest.tags | object |  |
| latest.context | object |  |
| latest.service | string |  |
| latest.environment | string |  |
| latest.release | string \| null |  |
| latest.instance | string |  |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 503 The monitoring service cannot be reached right now. Nothing is lost; try again in a few minutes.

### Resolve, ignore or reopen an issue

PATCH`/monitoring/projects/{project}/issues/{fingerprint}`

Account scope monitoring.write Limited to 60 per minute

Sets the issue's status. A resolved issue that happens again goes back to `unresolved` with `regressed_at` set (and, if the regression alert is on, you are emailed). An ignored issue stays ignored.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |
| fingerprintrequired | string | The issue's `fingerprint`. |

Body

| Name | Type | Description |
| --- | --- | --- |
| statusrequired | one of 'resolved', 'ignored', 'unresolved' |  |

Example

```
curl -X PATCH "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/issues/{fingerprint}" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"status":"resolved"}'
```

Response 200The issue as it is now.

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| fingerprint | string |  |
| type | string | The exception's type, e.g. `KeyError`. |
| title | string | The first occurrence's message, at most 200 characters. |
| culprit | string \| null | The innermost frame in your own code. |
| status | one of 'unresolved', 'resolved', 'ignored' |  |
| handled | boolean | Whether the latest occurrence was caught by your code. |
| count | integer |  |
| count_24h | integer |  |
| first_seen | integer | Unix seconds. |
| last_seen | integer | Unix seconds. |
| regressed_at | integer \| null | When a resolved issue last came back, in Unix seconds. |
| first_release | string \| null |  |
| last_release | string \| null |  |
| environments | array of string |  |
| services | array of string |  |
| sparkline | array of integer | Hourly counts for the last 24 hours, oldest first. |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 422 Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.
- 429 Too many requests. Wait for the number of seconds in the `Retry-After` header, then try again.
- 503 The monitoring service cannot be reached right now. Nothing is lost; try again in a few minutes.

### List an issue's occurrences

GET`/monitoring/projects/{project}/issues/{fingerprint}/occurrences`

Account scope monitoring.read

Every time the issue happened, newest first, each with its stack trace, tags and context, and where it ran.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |
| fingerprintrequired | string | The issue's `fingerprint`. |
| page | integer | The page of results to return, starting at 1. |
| per_page | integer | How many occurrences to return on each page. |

Example

```
curl "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/issues/{fingerprint}/occurrences" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200A page of occurrences.

```
{
    "data": [
        {
            "id": 5521,
            "ts": 1760390405,
            "type": "KeyError",
            "message": "'user_id'",
            "handled": false,
            "stack": [
                {
                    "function": "on_order",
                    "module": "bot.cogs.orders",
                    "filename": "bot/cogs/orders.py",
                    "lineno": 88,
                    "in_app": true
                }
            ],
            "cause": null,
            "tags": {
                "command": "order"
            },
            "context": [],
            "service": "orders-bot",
            "environment": "production",
            "release": "1.4.2",
            "instance": "a3f9c2e1"
        }
    ],
    "pagination": {
        "total": 1312,
        "page": 1,
        "per_page": 25
    }
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| data | array of object |  |
| data\[\].id | integer |  |
| data\[\].ts | integer | Unix seconds. |
| data\[\].type | string |  |
| data\[\].message | string |  |
| data\[\].handled | boolean |  |
| data\[\].stack | array of object | The stack frames, outermost first. |
| data\[\].cause | object \| null | The exception this one was raised from, in the same shape. |
| data\[\].tags | object |  |
| data\[\].context | object |  |
| data\[\].service | string |  |
| data\[\].environment | string |  |
| data\[\].release | string \| null |  |
| data\[\].instance | string |  |
| pagination | object |  |
| pagination.total | integer |  |
| pagination.page | integer |  |
| pagination.per_page | integer |  |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 503 The monitoring service cannot be reached right now. Nothing is lost; try again in a few minutes.

### List events

GET`/monitoring/projects/{project}/events`

Account scope monitoring.read

The events your application recorded (deploys, sign-ups, anything you send with `event()`), and those of linked servers (`server.crashed`, `server.started` and so on), newest first. Page back with `before`, using the `next` of the previous page.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |
| range | one of '1h', '6h', '24h', '7d', '30d', '90d', '1y' | How far back to look, ending now. Leave it out and send `from` and `to` for any other span. |
| from | integer | The start of the span, in Unix seconds. Used only without `range`; defaults to a day before `to`. |
| to | integer | The end of the span, in Unix seconds. Used only without `range`; defaults to now. |
| name | string | Only events with this name. |
| before | integer | Only events older than this event `id`. |
| limit | integer | How many events to return. |

Example

```
curl "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/events" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200The events.

```
{
    "data": [
        {
            "id": 812,
            "ts": 1760390410,
            "name": "deploy",
            "service": "orders-bot",
            "environment": "production",
            "attributes": {
                "version": "1.4.2"
            }
        }
    ],
    "next": 799
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| data | array of object |  |
| data\[\].id | integer |  |
| data\[\].ts | integer | Unix seconds. |
| data\[\].name | string |  |
| data\[\].service | string |  |
| data\[\].environment | string |  |
| data\[\].attributes | object |  |
| next | integer \| null | The `before` for the next page, or null at the end. |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 422 Some fields were missing or invalid. There is one error per problem, and `meta.source_field` names the field.
- 503 The monitoring service cannot be reached right now. Nothing is lost; try again in a few minutes.

### Get a project's usage

GET`/monitoring/projects/{project}/usage`

Account scope monitoring.read

How much of its limits the project has used today (the UTC day), how many metric series it has, what was dropped for being over a limit, and roughly how much it stores.

Parameters

| Name | Type | Description |
| --- | --- | --- |
| projectrequired | string (uuid) | The project's `uuid`. |

Example

```
curl "https://sillydev.co.uk/panel/api/client/monitoring/projects/{project}/usage" \
  -H "Authorization: Bearer $SILLYDEV_API_KEY" \
  -H "Accept: application/json"
```

Response 200The usage.

```
{
    "series": {
        "used": 31,
        "limit": 40
    },
    "today": {
        "errors": {
            "used": 120,
            "limit": 5000
        },
        "events": {
            "used": 40,
            "limit": 10000
        },
        "slow": {
            "used": 3,
            "limit": 2000
        },
        "requests": 8123
    },
    "dropped_today": {
        "series_limit": 12
    },
    "storage_bytes": 2101234
}
```

**Every field in the response**

| Name | Type | Description |
| --- | --- | --- |
| series | object |  |
| series.used | integer |  |
| series.limit | integer |  |
| today | object |  |
| today.errors | object |  |
| today.errors.used | integer |  |
| today.errors.limit | integer |  |
| today.events | object |  |
| today.events.used | integer |  |
| today.events.limit | integer |  |
| today.slow | object |  |
| today.slow.used | integer |  |
| today.slow.limit | integer |  |
| today.requests | integer |  |
| dropped_today | object | Items dropped today, by reason (e.g. `series_limit`, `error_quota`). |
| storage_bytes | integer | An estimate of what the project stores. |

Errors

- 401 No API key was sent, or it is wrong, expired or deleted.
- 403 The key is valid but may not do this: it lacks the permission or account scope, it is limited to other servers or IP addresses, or the account may not do it at all.
- 404 There is no such resource, or the key cannot see it. Features that are switched off answer 404 too.
- 503 The monitoring service cannot be reached right now. Nothing is lost; try again in a few minutes.

Read next

- [Authentication Create a key, limit what it can do, and keep it safe.](https://sillydev.co.uk/docs/panel/authentication)
- [Keys Server keys, browser keys and the websites allowed to use them.](https://sillydev.co.uk/docs/monitoring/keys)
