> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sitepulse.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Resources

> Field-by-field schemas for users, teams, sites, checks, issues, and reports

JSON shapes returned by v1 API resources.

## User

Returned on `GET /me` and nested on some issue responses.

| Field               | Type           | Description            |
| ------------------- | -------------- | ---------------------- |
| `name`              | string         | Display name           |
| `email`             | string         | Email address          |
| `email_verified_at` | string \| null | ISO 8601 when verified |

### Example

```json theme={null}
{
  "name": "John Doe",
  "email": "john@example.com",
  "email_verified_at": "2026-05-28T10:00:00+00:00"
}
```

## Team

| Field           | Type    | Description                              |
| --------------- | ------- | ---------------------------------------- |
| `uuid`          | string  | Team UUID (use in `/teams/{team}` paths) |
| `name`          | string  | Team name                                |
| `sites_count`   | integer | Present when counted                     |
| `members_count` | integer | Members including owner, when counted    |
| `limits`        | object  | Plan limits (see below)                  |
| `created_at`    | string  | ISO 8601                                 |
| `updated_at`    | string  | ISO 8601                                 |

### Team limits object

| Field                           | Type            | Description                                                                                           |
| ------------------------------- | --------------- | ----------------------------------------------------------------------------------------------------- |
| `plan`                          | string          | Plan key (`starter`, `growth`, `agency`)                                                              |
| `sites`                         | object          | `{ "used", "limit", "remaining" }` summary (`limit`/`remaining` are `null` when unlimited)            |
| `seats`                         | object          | Seat usage: `members`, `pending_invitations`, plus `used`, `limit`, `remaining`                       |
| `manual_checks`                 | object          | Monthly on-demand check `{ "used", "limit", "remaining" }` summary (JSON key remains `manual_checks`) |
| `enabled_checks`                | object          | `{ "allowed": ["status", ...] }` tools available to the team                                          |
| `minimum_check_cadence_minutes` | integer \| null | Fastest allowed automatic cadence                                                                     |
| `history_retention_days`        | integer \| null | How long check history is kept                                                                        |

### Example

```json theme={null}
{
  "uuid": "01JZ7VQ3J7Y5S8N9P0Q1R2S3T4",
  "name": "Acme Inc",
  "sites_count": 12,
  "members_count": 5,
  "limits": {
    "plan": "growth",
    "sites": {
      "used": 12,
      "limit": 25,
      "remaining": 13
    },
    "seats": {
      "members": 5,
      "pending_invitations": 1,
      "used": 6,
      "limit": 10,
      "remaining": 4
    },
    "manual_checks": {
      "used": 42,
      "limit": 250,
      "remaining": 208
    },
    "enabled_checks": {
      "allowed": ["status", "ssl", "dns", "broken-links", "performance"]
    },
    "minimum_check_cadence_minutes": 5,
    "history_retention_days": 90
  },
  "created_at": "2026-01-15T10:00:00+00:00",
  "updated_at": "2026-05-28T14:30:00+00:00"
}
```

## Team monitoring

Returned under `data` by `GET /teams/{team}/monitoring` and `PATCH /teams/{team}/monitoring`.

| Field                           | Type            | Description                                                                               |
| ------------------------------- | --------------- | ----------------------------------------------------------------------------------------- |
| `settings`                      | object          | Normalized monitoring settings: `tools`, `request_header`, `quiet_time`, and `escalation` |
| `cadence_presets`               | array           | Available cadence options with `minutes`, `label`, and `disabled` (plan-gated)            |
| `minimum_check_cadence_minutes` | integer \| null | Fastest cadence allowed by the team's plan                                                |
| `allowed_tools`                 | array           | Tools the team can configure, with per-tool cadence floors                                |
| `failure_threshold_presets`     | array           | Status failures-to-open presets (`instant`, `aggressive`, `conservative`)                 |
| `escalation_interval_presets`   | array           | Escalation reminder options (`immediately`, `15m` through `daily`)                        |
| `dns_record_types`              | string\[]       | Supported DNS record types for `monitored_record_types`                                   |
| `status_incident_code_options`  | array           | Selectable status codes with `code`, `label`, and `group` (`client` or `server`)          |

### Example

```json theme={null}
{
  "settings": {
    "tools": {
      "status": {
        "enabled": true,
        "cadence_minutes": 5,
        "settings": {
          "incident_status_codes": [400, 401, 403, 404, 405, 408, 410, 429, 500, 501, 502, 503, 504, 521, 522, 523, 524],
          "failures_to_open": 2,
          "successes_to_resolve": 1,
          "confirmation_retry_minutes": 2,
          "incident_follow_up_minutes": 5
        }
      },
      "ssl": {
        "enabled": true,
        "cadence_minutes": 1440,
        "settings": { "expiry_days": 14 }
      },
      "dns": {
        "enabled": true,
        "cadence_minutes": 1440,
        "settings": {
          "hard_failures_only": true,
          "monitored_record_types": ["A", "AAAA", "CNAME", "MX", "NS", "TXT"]
        }
      },
      "broken-links": {
        "enabled": true,
        "cadence_minutes": 1440,
        "settings": {
          "min_broken_count": 5,
          "ignore_paths": []
        }
      },
      "performance": {
        "enabled": true,
        "cadence_minutes": 1440,
        "settings": {
          "url": null,
          "min_score": 50,
          "max_ttfb_ms": 4000
        }
      }
    },
    "request_header": { "name": null, "value": null },
    "quiet_time": { "enabled": false, "starts_at": "22:00", "ends_at": "07:00" },
    "escalation": { "enabled": false, "intervals": [] }
  },
  "minimum_check_cadence_minutes": 5,
  "failure_threshold_presets": [
    { "key": "instant", "label": "Instant", "failures_to_open": 1 }
  ],
  "escalation_interval_presets": [
    { "key": "15m", "label": "15 minutes", "minutes": 15 }
  ],
  "dns_record_types": ["A", "AAAA", "CNAME", "MX", "NS", "TXT"],
  "status_incident_code_options": [
    { "code": 400, "label": "Bad Request", "group": "client" },
    { "code": 401, "label": "Unauthorized", "group": "client" },
    { "code": 403, "label": "Forbidden", "group": "client" },
    { "code": 404, "label": "Not Found", "group": "client" },
    { "code": 405, "label": "Method Not Allowed", "group": "client" },
    { "code": 408, "label": "Request Timeout", "group": "client" },
    { "code": 410, "label": "Gone", "group": "client" },
    { "code": 429, "label": "Too Many Requests", "group": "client" },
    { "code": 500, "label": "Internal Server Error", "group": "server" },
    { "code": 501, "label": "Not Implemented", "group": "server" },
    { "code": 502, "label": "Bad Gateway", "group": "server" },
    { "code": 503, "label": "Service Unavailable", "group": "server" },
    { "code": 504, "label": "Gateway Timeout", "group": "server" },
    { "code": 521, "label": "Web Server Is Down", "group": "server" },
    { "code": 522, "label": "Connection Timed Out", "group": "server" },
    { "code": 523, "label": "Origin Is Unreachable", "group": "server" },
    { "code": 524, "label": "A Timeout Occurred", "group": "server" }
  ]
}
```

## Site

| Field            | Type           | Description                             |
| ---------------- | -------------- | --------------------------------------- |
| `uuid`           | string         | Site identifier in API paths            |
| `team_uuid`      | string         | Owning team UUID                        |
| `name`           | string         | Display name                            |
| `url`            | string         | Canonical monitored URL                 |
| `domain`         | string         | Hostname derived from URL               |
| `notes`          | string \| null | Team notes                              |
| `js_rendered`    | boolean        | Use JS rendering for broken-link crawls |
| `is_pinned`      | boolean        | Pinned on sites list                    |
| `enabled_checks` | string\[]      | Enabled tool values                     |
| `monitoring`     | object         | See monitoring object below             |
| `issue_settings` | object         | Resolved issue settings for the site    |
| `latest_checks`  | object         | Latest check per tool, when loaded      |
| `reports`        | object         | Absolute URLs to report endpoints       |
| `created_at`     | string         | ISO 8601                                |
| `updated_at`     | string         | ISO 8601                                |

### Monitoring object

| Field      | Type   | Description                                                       |
| ---------- | ------ | ----------------------------------------------------------------- |
| `settings` | object | Resolved site monitoring settings. Same shape as team `settings`. |

### Latest checks object

Keys are tool values (`status`, `ssl`, `dns`, `broken-links`, `performance`). Values are [Check](#check) objects or `null` if no check exists.

### Reports object

| Field         | Type         |
| ------------- | ------------ |
| `uptime`      | string (URL) |
| `performance` | string (URL) |

These are fully qualified route URLs for the report endpoints on this site.

### Issue settings object

Returned as `issue_settings` on Site resources. The response is resolved for the site, so it includes team defaults plus any per-site overrides.

<Note>
  PATCH requests use `monitoring_settings` for cadence and rule overrides, and `dns_expected_records` for the per-site DNS baseline. The response returns the normalized issue shape as `issue_settings`.
</Note>

| Field                                      | Type            | Description                                                                           |
| ------------------------------------------ | --------------- | ------------------------------------------------------------------------------------- |
| `enabled_tools`                            | string\[]       | Tools that can open issues (`status`, `ssl`, `dns`, `broken-links`, `performance`)    |
| `status.failures_to_open`                  | integer         | Failed status checks before opening an issue                                          |
| `status.incident_status_codes`             | integer\[]      | HTTP response codes that count as failed status checks; request failures always count |
| `status.successes_to_resolve`              | integer         | Successful status checks before resolving                                             |
| `status.confirmation_retry_minutes`        | integer         | Minutes before confirmation retry (1–5)                                               |
| `status.incident_follow_up_minutes`        | integer         | Minutes between incident follow-up checks (1–60)                                      |
| `ssl.expiry_days`                          | integer         | Days before expiry to open SSL warning issue                                          |
| `ssl.failures_to_open`                     | integer         | Failed SSL checks before opening an issue                                             |
| `ssl.confirmation_retry_minutes`           | integer         | Minutes before SSL confirmation retry (1–5)                                           |
| `links.min_broken_count`                   | integer         | Minimum broken URLs to breach threshold                                               |
| `links.consecutive_breaches_to_open`       | integer         | Consecutive breached crawls before opening issue                                      |
| `links.ignore_paths`                       | string\[]       | URL path patterns excluded from broken-link crawls                                    |
| `links.ignore_external_links`              | boolean         | Exclude links outside the monitored site host                                         |
| `links.ignore_redirects`                   | boolean         | Exclude redirect responses from broken-link counts                                    |
| `performance.url`                          | string \| null  | Page URL audited instead of the site root                                             |
| `performance.min_score`                    | integer         | Minimum acceptable score (1–100)                                                      |
| `performance.max_response_time_ms`         | integer         | Legacy max response time (ms); normalized with `max_ttfb_ms`                          |
| `performance.max_ttfb_ms`                  | integer         | Maximum time to first byte in milliseconds                                            |
| `performance.max_load_time_seconds`        | integer \| null | Maximum Time to Interactive in seconds                                                |
| `performance.consecutive_breaches_to_open` | integer         | Consecutive breached checks before opening issue                                      |
| `dns.hard_failures_only`                   | boolean         | Only open DNS issues on lookup failures when `true`                                   |
| `dns.failures_to_open`                     | integer         | Failed DNS checks before opening an issue                                             |
| `dns.confirmation_retry_minutes`           | integer         | Minutes before DNS confirmation retry (1–5)                                           |
| `dns.monitored_record_types`               | string\[]       | DNS record types to watch for changes                                                 |
| `dns.expected_records`                     | object          | Map of record type → array of expected values                                         |
| `quiet_time.enabled`                       | boolean         | Suppress outbound issue alerts during a daily window                                  |
| `quiet_time.starts_at`                     | string          | Quiet time start in `H:i` format                                                      |
| `quiet_time.ends_at`                       | string          | Quiet time end in `H:i` format                                                        |
| `escalation.enabled`                       | boolean         | Send follow-up reminders for open issues                                              |
| `escalation.intervals`                     | integer\[]      | Reminder schedule in minutes (`0` = immediately, `15`, `30`, `60`, `360`, `1440`)     |

### Example

```json theme={null}
{
  "uuid" : "9d4e2c8f-1234-5678-9abc-def012345678",
  "team_uuid": "01JZ7VQ3J7Y5S8N9P0Q1R2S3T4",
  "name": "Example Site",
  "url": "https://example.com",
  "domain": "example.com",
  "notes": "Production website",
  "js_rendered": false,
  "is_pinned": true,
  "enabled_checks": ["status", "ssl", "performance"],
  "monitoring": {
    "settings": {
      "tools": {
        "status": {
          "enabled": true,
          "cadence_minutes": 5,
          "settings": {
            "incident_status_codes": [400, 401, 403, 404, 405, 408, 410, 429, 500, 501, 502, 503, 504, 521, 522, 523, 524]
          }
        },
        "ssl": {
          "enabled": true,
          "cadence_minutes": 1440,
          "settings": { "expiry_days": 14 }
        },
        "performance": {
          "enabled": true,
          "cadence_minutes": 1440,
          "settings": {
            "url": null,
            "min_score": 50,
            "max_ttfb_ms": 4000
          }
        }
      },
      "request_header": { "name": null, "value": null },
      "quiet_time": { "enabled": false, "starts_at": "22:00", "ends_at": "07:00" },
      "escalation": { "enabled": false, "intervals": [] }
    }
  },
  "issue_settings": {
    "enabled_tools": ["status", "ssl", "performance"],
    "status": {
      "incident_status_codes": [400, 401, 403, 404, 405, 408, 410, 429, 500, 501, 502, 503, 504, 521, 522, 523, 524],
      "failures_to_open": 2,
      "successes_to_resolve": 1,
      "confirmation_retry_minutes": 2,
      "incident_follow_up_minutes": 5
    },
    "ssl": {
      "expiry_days": 14,
      "failures_to_open": 2,
      "confirmation_retry_minutes": 2
    },
    "performance": {
      "url": null,
      "min_score": 50,
      "max_response_time_ms": 4000,
      "max_ttfb_ms": 4000
    },
    "quiet_time": { "enabled": false, "starts_at": "22:00", "ends_at": "07:00" },
    "escalation": { "enabled": false, "intervals": [] }
  },
  "reports": {
    "uptime": "https://app.sitepulse.dev/api/v1/sites/9d4e2c8f.../reports/uptime",
    "performance": "https://app.sitepulse.dev/api/v1/sites/9d4e2c8f.../reports/performance"
  },
  "created_at": "2026-05-20T10:00:00+00:00",
  "updated_at": "2026-05-28T14:30:00+00:00"
}
```

## Check

| Field          | Type           | Description                                                      |
| -------------- | -------------- | ---------------------------------------------------------------- |
| `uuid`         | string         | Check identifier                                                 |
| `type`         | string         | Tool value                                                       |
| `status`       | string         | `pending`, `completed`, `failed`, `skipped`                      |
| `automatic`    | boolean        | Scheduled vs on-demand run                                       |
| `run_reason`   | string \| null | `scheduled`, `confirmation_retry`, `incident_follow_up` when set |
| `site`         | object \| null | `{ uuid, name, url, domain }` when loaded                        |
| `result`       | mixed          | Tool-specific payload; see [Check results](/api/check-results)   |
| `error`        | mixed          | Error payload when failed                                        |
| `created_at`   | string         | ISO 8601                                                         |
| `updated_at`   | string         | ISO 8601                                                         |
| `completed_at` | string \| null | ISO 8601 when finished                                           |

### Example

```json theme={null}
{
  "uuid": "9d4e2c8f-abcd-5678-9abc-def012345678",
  "type": "status",
  "status": "completed",
  "automatic": false,
  "run_reason": null,
  "site": {
    "uuid": "9d4e2c8f-1234-5678-9abc-def012345678",
    "name": "Example Site",
    "url": "https://example.com",
    "domain": "example.com"
  },
  "result": {
    "up": true,
    "code": 200,
    "url": "https://example.com",
    "effective_url": "https://example.com",
    "response_time": 142.37,
    "redirected": false,
    "redirect_count": 0
  },
  "error": null,
  "created_at": "2026-05-28T14:30:00+00:00",
  "updated_at": "2026-05-28T14:30:05+00:00",
  "completed_at": "2026-05-28T14:30:05+00:00"
}
```

## Issue

Issues represent monitoring incidents opened by automatic checks. The API exposes read-only access for integrations that need to correlate webhook notifications or query incident history.

| Field               | Type           | Description                                                                        |
| ------------------- | -------------- | ---------------------------------------------------------------------------------- |
| `uuid`              | string         | Issue identifier                                                                   |
| `team_uuid`         | string         | Owning team UUID                                                                   |
| `type`              | string         | Check tool that detected the problem                                               |
| `status`            | string         | `open`, `acknowledged`, or `resolved`                                              |
| `severity`          | string         | `critical`, `warning`, `info`                                                      |
| `fingerprint`       | string         | Stable key for deduplication (e.g. `status:down`, `ssl:expiring`)                  |
| `summary`           | string         | Human-readable summary                                                             |
| `context`           | object \| null | Structured evaluation payload from the check                                       |
| `site`              | Site \| null   | Affected site when loaded                                                          |
| `check`             | Check \| null  | Latest check tied to the issue                                                     |
| `previous_check`    | Check \| null  | Prior check used for comparison when loaded                                        |
| `acknowledged_by`   | User \| null   | User who acknowledged the issue                                                    |
| `resolved_by`       | User \| null   | User who resolved the issue (or null when resolved automatically)                  |
| `timeline`          | array          | Lifecycle events (`opened`, `acknowledged`, `resolved`) with timestamps and actors |
| `is_active`         | boolean        | `true` when status is `open` or `acknowledged`                                     |
| `opened_at`         | string         | ISO 8601                                                                           |
| `acknowledged_at`   | string \| null | ISO 8601                                                                           |
| `resolved_at`       | string \| null | ISO 8601 when recovered                                                            |
| `last_evaluated_at` | string \| null | ISO 8601                                                                           |
| `created_at`        | string         | ISO 8601                                                                           |
| `updated_at`        | string         | ISO 8601                                                                           |

### Example

```json theme={null}
{
  "uuid": "9d4e2c8f-issue-5678-9abc-def012345678",
  "team_uuid": "01JZ7VQ3J7Y5S8N9P0Q1R2S3T4",
  "type": "status",
  "status": "open",
  "severity": "critical",
  "fingerprint": "status:down",
  "summary": "Example is down (HTTP 500)",
  "context": {
    "response_code": 500
  },
  "timeline": [
    { "key": "opened", "timestamp": "2026-05-28T14:00:00+00:00", "user": null }
  ],
  "is_active": true,
  "opened_at": "2026-05-28T14:00:00+00:00",
  "acknowledged_at": null,
  "resolved_at": null,
  "last_evaluated_at": "2026-05-28T14:30:00+00:00",
  "created_at": "2026-05-28T14:00:00+00:00",
  "updated_at": "2026-05-28T14:30:00+00:00"
}
```

## Uptime report

Returned by `GET /sites/{site}/reports/uptime`.

```json theme={null}
{
  "data": {
    "days": [
      {
        "date": "2026-05-28T00:00:00+00:00",
        "uptime_percentage": 99.5,
        "response_time": 142,
        "total_checks": 288,
        "up_checks": 287
      }
    ],
    "total_uptime_percentage": 99.2,
    "average_response_time": 168
  }
}
```

| Field                      | Type            | Description                                                 |
| -------------------------- | --------------- | ----------------------------------------------------------- |
| `days[].date`              | string          | Day start (ISO 8601)                                        |
| `days[].uptime_percentage` | float \| null   | Percentage of up checks; `null` on days with no checks      |
| `days[].response_time`     | integer \| null | Slowest response time that day in ms; `null` when no checks |
| `days[].total_checks`      | integer         | Status checks recorded that day                             |
| `days[].up_checks`         | integer         | Checks that returned up                                     |
| `total_uptime_percentage`  | float \| null   | Overall up percentage across the range                      |
| `average_response_time`    | integer \| null | Average daily response time in ms across the range          |

<Info>
  * Based on **automatic** completed `status` checks
  * Days without checks have `uptime_percentage: null`, `response_time: null`, and `total_checks: 0`
  * Default range: 90 days; override with `?days=` (max 365)
</Info>

## Performance report

Returned by `GET /sites/{site}/reports/performance`.

```json theme={null}
{
  "data": {
    "days": [
      {
        "date": "2026-05-28T00:00:00+00:00",
        "performance_score": 87.5,
        "response_time": 420,
        "speed": 3.2,
        "total_checks": 24
      }
    ],
    "average_performance_score": 85.1,
    "average_response_time": 450,
    "average_speed": 3.4,
    "total_checks": 720
  }
}
```

| Field                       | Type            | Description                                              |
| --------------------------- | --------------- | -------------------------------------------------------- |
| `days[].date`               | string          | Day start (ISO 8601)                                     |
| `days[].performance_score`  | float \| null   | Average Lighthouse score that day; `null` when no checks |
| `days[].response_time`      | integer \| null | Average response time that day in ms                     |
| `days[].speed`              | float \| null   | Average Speed Index that day in seconds                  |
| `days[].total_checks`       | integer         | Performance checks recorded that day                     |
| `average_performance_score` | float \| null   | Average score across the range                           |
| `average_response_time`     | integer \| null | Average response time across the range (ms)              |
| `average_speed`             | float \| null   | Average Speed Index across the range (seconds)           |
| `total_checks`              | integer         | Total performance checks across the range                |

<Info>
  * Based on **automatic** completed `performance` checks
  * Days without checks have `null` metrics and `total_checks: 0`
  * Default range: 30 days; override with `?days=` (max 365)
</Info>

## Bulk site create response

`POST /teams/{team}/sites/bulk` returns:

```json theme={null}
{
  "data": {
    "created": [ /* Site resources */ ],
    "skipped": [],
    "failed": [
      { "url": "https://invalid", "error": "..." }
    ]
  }
}
```

## See also

* [Endpoints](/api/endpoints)
* [Check result payloads](/api/check-results)
