# Sites & Strings

A **site** describes a PV system once and completely. After that you query forecasts and
historical data solely via the `site_id` — without sending the configuration every time.

:::tip
This page explains the **data model**. The actual endpoints (create, update, delete, retrieve)
are in the [API Reference](/api). Programmatic management is described by the
[Sites API](/en/v2/enterprise/sites-api).
:::

## Structure of a site

A site consists of three parts:

1. **Location** — `latitude`, `longitude` (required). `elevation`, `timezone` and the terrain
   horizon are determined automatically.
2. **Strings** — a list of PV strings (sub-arrays) with their own geometry.
3. **Config** — optional, system-wide fine configuration. Only explicitly set values are
   stored; everything else follows the current system defaults.
``
```json title="Create a site (body)"
{
  "name": "Roof South",
  "latitude": 48.8566,
  "longitude": 2.3522,
  "strings": [
    {
      "slope": 30,
      "orientation": 180,
      "power_kw": 8
    },
    {
      "slope": 30,
      "orientation": 90,
      "power_kw": 4
    }
  ],
  "config": {
    "modules": {
      "technology": "topcon"
    },
    "tracking": {
      "type": "fixed"
    }
  }
}
```

## PV strings

Each string is a standalone sub-array. The site sums the power of all strings. When a site is
created, a default string (10 kWp, 180° south, 30° tilt) is added automatically, which you can edit
at any time.

| Field                | Meaning                                                                |
|----------------------|------------------------------------------------------------------------|
| `id`                 | Stable string id (e.g. `str_9f3a1c08`). Server-assigned and read-only. |
| `slope`              | Module tilt in degrees (0 = horizontal, 90 = vertical).                |
| `orientation`        | Azimuth in degrees (0 = N, 90 = E, 180 = S, 270 = W).                  |
| `power_kw`           | Peak power of the string in kW.                                        |
| `gcr`                | Ground coverage ratio for row shading (optional).                      |
| `near_field_shading` | Near-field shading of the string (optional).                           |

:::note
Each string gets a **stable `id`** (e.g. `str_9f3a1c08`), minted by the server and returned with
the site. It is the join key for per-string data — the forecast/historical `strings` block carries
it as `string_id`, and measurement uploads are addressed by it.

The `id` is **read-only**: it is ignored on create. On a PATCH of `strings` (which replaces the
whole array), **echo each string's `id` to keep it** — and the data attached to it, e.g.
measurements. A string whose `id` is omitted is treated as removed; one with no `id` is treated as
new. Strings also still carry a positional `string_index`, so reading the site and forecast from the
same point in time keeps the order consistent.
:::

## Configuration (config)

The system-wide config is organized into groups. All fields are optional — if a group is
missing, the system defaults apply.

| Group      | Content                                                                                                   |
|------------|-----------------------------------------------------------------------------------------------------------|
| `modules`  | Module technology (`monosi`, `multisi`, `perc`, `topcon`, `cdte`), temperature coefficient, install year. |
| `mounting` | Mounting type (`open`, `mix`, `isol`) and height above ground.                                            |
| `inverter` | Inverter clipping (max/min in % of DC rated power).                                                       |
| `losses`   | Losses & gains: cabling, conversion, albedo, snow sliding, diffuse model.                                 |
| `shading`  | Use terrain horizon (`use_terrain_horizon`) and sky obstructions (`sky_obstruction`).                     |
| `tracking` | Tracker type (`fixed`, `single_axis`, `dual_axis`) and axis parameters.                                   |

:::note
**Sparse storage:** Only the values you explicitly set are stored. If we improve a default
globally (e.g. a new irradiance model), existing sites benefit automatically.
:::

The exact value ranges and defaults of each group are in the [API Reference](/api).

## Automatically determined fields

From the coordinates, the following are determined and stored automatically on creation
(and when the location changes):

- **`elevation`** — height above sea level in meters.
- **`timezone`** — IANA timezone (e.g. `Europe/Berlin`), the basis for local timestamps.
- **Terrain horizon** — feeds into the shading calculation.

## Temporary sites

With `temporary: true` on creation you mark a site as temporary/experimental. This feature requires a
suitable plan. A temporary site is automatically deleted **31 days** after it is created. To keep it,
restore it before then via the web app or via  `POST /sites/{id}/restore` — this cancels the pending deletion and makes
the site permanent.

## Limits

| Limit           | Behavior                                                                |
|-----------------|-------------------------------------------------------------------------|
| Site limit      | Maximum number of sites (can be `unmetered`).                           |
| String limit    | Maximum strings per site.                                               |
| Location change | Fixed at **1 location change per 30 days** per site (plan-independent). |

## Deletion & restore

Deleted sites are first marked as "pending deletion" (`deleted_at` set) and only
**permanently removed 30 days later**. Within this window they can be restored.
Details in the [API Reference](/api).
