MENU navbar-image

Introduction

API REST di SunPilot: anagrafica impianti fotovoltaici e telemetria canonica, vendor-agnostic.

L'API v1 di SunPilot espone anagrafica impianti fotovoltaici e telemetria canonica del tuo tenant, qualunque sia il vendor dell'hardware in campo.

Base URL: https://sunpilot.cloud/api/v1 · Versioning: il prefisso /v1 è il contratto; le evoluzioni incompatibili arriveranno come /v2.

Convenzioni:

Authenticating requests

To authenticate requests, include an Authorization header with the value "Bearer {ACCESS_TOKEN}".

All authenticated endpoints are marked with a requires authentication badge in the documentation below.

Le credenziali OAuth2 (client id/secret) si ottengono su richiesta scrivendo a info@sunpilot.cloud. Ottenute le credenziali, il flusso è authorization code + PKCE: autorizzazione su /oauth/authorize, scambio del codice su /oauth/token, refresh su /oauth/token/refresh. Scope disponibili: read (lettura di anagrafica e telemetria) e write (scrittura di anagrafica; le route di scrittura richiedono anche un ruolo abilitato alla scrittura nel tenant). Lo scope command è riservato per i futuri comandi verso i device e oggi non è consumato da nessun endpoint.

Allarmi

Allarmi canonici (ADR-027): stato corrente del parco, popolato da sunpilot:scan-alarms. Diverso da GET /alarms (regola "device scollegato" a 30 minuti, non persistita) — qui la soglia è la staleness canonica (6h/24h).

Elenca gli allarmi attivi

requires authentication

Solo allarmi correnti (non ancora rientrati), ordinati per severità decrescente (critical prima di warning prima di info).

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/alarms/canonical" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/alarms/canonical';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/alarms/canonical"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "id": "9c3b1e2a-...",
            "site_id": "7a1f...",
            "site_name": "Villa Bianchi",
            "device_id": "4b2e...",
            "device_name": "Shelly Pro 3EM",
            "code": "device_offline",
            "severity": "warning",
            "status": "raised",
            "message": "Nessuna misura da 9h",
            "raised_at": "2026-07-13T08:00:00.000000Z",
            "last_seen_at": "2026-07-13T11:00:00.000000Z"
        }
    ]
}
 

Request   

GET api/v1/alarms/canonical

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Clienti impianto

Gestione degli inviti/accessi cliente-per-impianto (design doc 2026-07-17-end-customer-site-access-design.md). Riservato a owner/admin.

POST api/v1/sites/{site_id}/customer-invitations

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"email\": \"gbailey@example.net\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'email' => 'gbailey@example.net',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "email": "gbailey@example.net"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/sites/{site_id}/customer-invitations

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

Body Parameters

email   string     

Must be a valid email address. Must not be greater than 255 characters. Example: gbailey@example.net

GET api/v1/sites/{site_id}/customer-invitations

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/customer-invitations

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

DELETE api/v1/sites/{site_id}/customer-invitations/{siteCustomerAccess_id}

requires authentication

Example request:
curl --request DELETE \
    "https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations/architecto';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/customer-invitations/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request   

DELETE api/v1/sites/{site_id}/customer-invitations/{siteCustomerAccess_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

siteCustomerAccess_id   string     

The ID of the siteCustomerAccess. Example: architecto

Control Center

Riepilogo del parco impianti del tenant: produzione, stato online, allarmi attivi, autoconsumo/autosufficienza, performance vs atteso PVGIS, risparmio/CO2 stimati, batteria, confronto con ieri, ultimi eventi di allarme. Endpoint separato da /dashboard/weather e /dashboard/production-series (design doc 2026-07-24-async-page-loading-design.md) così il frontend può caricarli in parallelo invece di attendere un'unica risposta monolitica: KPI e trend periodici sono calcolati in batch per l'intero parco (SiteKpis::computeMany, MonthlyEnergyBuckets::totalsByMetricMany); resta per-sito solo il contributo diagnostica (cache 1h, chiamata PVGIS non batchabile).

Riepilogo del parco impianti

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/dashboard/summary" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/dashboard/summary';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/dashboard/summary"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "totals": {
        "sites": 4,
        "online": 3,
        "production_today_wh": 184200,
        "active_alarms": 1,
        "alarms_by_severity": {
            "critical": 0,
            "warning": 1,
            "info": 0
        },
        "self_consumption_wh": 92100,
        "self_consumption_rate": 0.74,
        "self_sufficiency": 0.5,
        "diagnostics_alerts": 1,
        "performance": {
            "actual_kwh": 12500,
            "expected_kwh": 13800,
            "ratio": 0.906
        },
        "savings": {
            "annual_eur": 3200,
            "co2_kg": 6100
        },
        "trend": {
            "production_yesterday_wh": 176000,
            "production_delta_pct": 0.047,
            "production_week_wh": 620000,
            "production_week_prev_wh": 590000,
            "production_week_delta_pct": 0.051,
            "production_month_wh": 2450000,
            "production_month_prev_wh": 2300000,
            "production_month_delta_pct": 0.065
        },
        "battery": {
            "sites_with_battery": 1,
            "avg_soc": 0.62,
            "charged_wh_today": 3200,
            "discharged_wh_today": 2100
        }
    },
    "sites": [
        {
            "id": "7a1f...",
            "name": "Villa Bianchi",
            "online": true,
            "cloud_connected": true,
            "latitude": 45.4642,
            "longitude": 9.19,
            "address": "Via Baldini 12, Milano",
            "production_today_wh": 12400,
            "alarms": {
                "count": 1,
                "worst_severity": "warning"
            },
            "diagnostics": {
                "severity": "warning",
                "title": "Performance 78%"
            },
            "performance_ratio": 0.906
        }
    ],
    "recent_events": [
        {
            "type": "raised",
            "site_name": "Capannone Rossi",
            "severity": "warning",
            "message": "Nessuna misura da 9h",
            "at": "2026-07-13T08:00:00.000000Z"
        }
    ],
    "edge_installations": [
        {
            "id": "9c2e...",
            "site_id": "7a1f...",
            "site_name": "Villa Bianchi",
            "label": "gateway-01",
            "status": "online",
            "last_sync_at": "2026-07-24T09:15:00.000000Z",
            "last_health_at": "2026-07-24T09:14:50.000000Z",
            "runtime_version": "1.4.2",
            "cpu_percent": 12.5,
            "ram_percent": 38,
            "disk_percent": 21,
            "temperature_c": 47.3,
            "driver_statuses": {
                "fusionsolar": "ok"
            }
        }
    ]
}
 

Request   

GET api/v1/dashboard/summary

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Meteo di riferimento del parco impianti

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/dashboard/weather" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/dashboard/weather';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/dashboard/weather"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "site_name": "Villa Bianchi",
    "temp_max": 28.5,
    "temp_min": 18.2,
    "radiation_sum": 24.1,
    "tomorrow": {
        "temp_max": 27,
        "temp_min": 17.5,
        "radiation_sum": 20
    }
}
 

Example response (200):


null
 

Request   

GET api/v1/dashboard/weather

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Andamento orario di produzione del parco impianti

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/dashboard/production-series" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/dashboard/production-series';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/dashboard/production-series"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


[
    {
        "hour": "00:00",
        "pv_production": 0,
        "grid_import": 1200,
        "battery_charge": 0,
        "battery_discharge": 0,
        "grid_export": 0
    },
    {
        "hour": "10:00",
        "pv_production": 4500,
        "grid_import": 300,
        "battery_charge": 0,
        "battery_discharge": 0,
        "grid_export": 900
    }
]
 

Request   

GET api/v1/dashboard/production-series

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/dashboard/opportunities-summary

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/dashboard/opportunities-summary" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/dashboard/opportunities-summary';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/dashboard/opportunities-summary"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/dashboard/opportunities-summary

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/dashboard/fleet

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/dashboard/fleet" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/dashboard/fleet';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/dashboard/fleet"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/dashboard/fleet

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Diagnostica

Dashboard diagnostica di portfolio: triage a scala su migliaia di impianti, con filtri, ordinamento e aggregati calcolati lato SQL sui campi persistiti da ScanDiagnosticsForSite (nessuna fetch live di PlantDiagnostics::analyze() per riga — vedi design doc 2026-07-24-diagnostica-portfolio-dashboard-design.md).

Elenca gli impianti con la loro diagnostica precalcolata

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/diagnostics?severity=critical&search=Rossi&sort=savings&per_page=25" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/diagnostics';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'severity' => 'critical',
            'search' => 'Rossi',
            'sort' => 'savings',
            'per_page' => '25',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/diagnostics"
);

const params = {
    "severity": "critical",
    "search": "Rossi",
    "sort": "savings",
    "per_page": "25",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/diagnostics

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

severity   string  optional    

Filtro esatto: critical|warning|info|ok. Example: critical

search   string  optional    

Ricerca case-insensitive sul nome impianto. Example: Rossi

sort   string  optional    

severity (default, critici prima) | savings (risparmio annuo desc, null in coda). Example: savings

per_page   integer  optional    

Risultati per pagina (1–200). Default: 25. Example: 25

Endpoints

POST api/v1/edge/enroll

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/edge/enroll" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"code\": \"b\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge/enroll';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'code' => 'b',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge/enroll"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "code": "b"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/edge/enroll

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

code   string     

Must not be greater than 32 characters. Example: b

POST api/v1/edge/heartbeat

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/edge/heartbeat" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"cpu_percent\": 1,
    \"ram_percent\": 22,
    \"disk_percent\": 7,
    \"temperature_c\": 16,
    \"runtime_version\": \"m\",
    \"device_states\": [
        {
            \"device_id\": \"a1a0a47d-e8c3-3cf0-8e6e-c1ff9dca5d1f\",
            \"state_type\": \"v\",
            \"state\": \"d\",
            \"raw_code\": 16,
            \"at\": \"2026-08-01T06:26:43\"
        }
    ]
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge/heartbeat';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'cpu_percent' => 1,
            'ram_percent' => 22,
            'disk_percent' => 7,
            'temperature_c' => 16,
            'runtime_version' => 'm',
            'device_states' => [
                ['device_id' => 'a1a0a47d-e8c3-3cf0-8e6e-c1ff9dca5d1f', 'state_type' => 'v', 'state' => 'd', 'raw_code' => 16, 'at' => '2026-08-01T06:26:43'],
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge/heartbeat"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "cpu_percent": 1,
    "ram_percent": 22,
    "disk_percent": 7,
    "temperature_c": 16,
    "runtime_version": "m",
    "device_states": [
        {
            "device_id": "a1a0a47d-e8c3-3cf0-8e6e-c1ff9dca5d1f",
            "state_type": "v",
            "state": "d",
            "raw_code": 16,
            "at": "2026-08-01T06:26:43"
        }
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/edge/heartbeat

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

cpu_percent   number  optional    

Must be at least 0. Must not be greater than 100. Example: 1

ram_percent   number  optional    

Must be at least 0. Must not be greater than 100. Example: 22

disk_percent   number  optional    

Must be at least 0. Must not be greater than 100. Example: 7

temperature_c   number  optional    

Range di sanità per la CPU di un gateway edge (non un sensore ambientale): oltre questi limiti è un valore malformato, non una lettura reale, e prima veniva accettato/graficato senza controllo. Must be at least -40. Must not be greater than 120. Example: 16

runtime_version   string  optional    

Must not be greater than 64 characters. Example: m

driver_statuses   object  optional    
device_states   object[]  optional    
device_id   string     

Must be a valid UUID. Example: a1a0a47d-e8c3-3cf0-8e6e-c1ff9dca5d1f

state_type   string     

Must not be greater than 64 characters. Example: v

state   string     

Must not be greater than 64 characters. Example: d

raw_code   integer  optional    

Example: 16

at   string     

Must be a valid date. Example: 2026-08-01T06:26:43

GET api/v1/edge/config

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/edge/config" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge/config';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge/config"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/edge/config

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

POST api/v1/edge/measurements

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/edge/measurements" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"measurements\": [
        {
            \"device_id\": \"architecto\",
            \"capability\": \"architecto\",
            \"metric\": \"architecto\",
            \"phase\": \"architecto\",
            \"value\": 4326.41688,
            \"unit\": \"architecto\",
            \"sampling\": \"architecto\",
            \"quality\": \"architecto\",
            \"timestamp_utc\": \"architecto\",
            \"source_driver\": \"architecto\",
            \"source_driver_version\": \"architecto\",
            \"schema_version\": \"architecto\"
        }
    ]
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge/measurements';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'measurements' => [
                [
                    'device_id' => 'architecto', 'capability' => 'architecto', 'metric' => 'architecto', 'phase' => 'architecto', 'value' => 4326.41688, 'unit' => 'architecto', 'sampling' => 'architecto', 'quality' => 'architecto', 'timestamp_utc' => 'architecto', 'source_driver' => 'architecto',
                    'source_driver_version' => 'architecto', 'schema_version' => 'architecto',
                ],
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge/measurements"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "measurements": [
        {
            "device_id": "architecto",
            "capability": "architecto",
            "metric": "architecto",
            "phase": "architecto",
            "value": 4326.41688,
            "unit": "architecto",
            "sampling": "architecto",
            "quality": "architecto",
            "timestamp_utc": "architecto",
            "source_driver": "architecto",
            "source_driver_version": "architecto",
            "schema_version": "architecto"
        }
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/edge/measurements

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

measurements   object[]     

Tetto arbitrario ma esplicito: senza un max, un batch enorme (o malformato) viene comunque collect()-ato e iterato in-process senza chunking — rischio di timeout/DoS da una singola unità Edge autenticata. 5000 righe copre ampiamente un sync periodico anche per un sito con molti device/metriche. Must not have more than 5000 items.

device_id   string     

Example: architecto

capability   string     

Example: architecto

metric   string     

Example: architecto

phase   string  optional    

Example: architecto

value   number     

Example: 4326.41688

unit   string     

Example: architecto

sampling   string     

Example: architecto

quality   string     

Example: architecto

timestamp_utc   string     

Example: architecto

source_driver   string     

Example: architecto

source_driver_version   string  optional    

Example: architecto

schema_version   string  optional    

Example: architecto

GET api/v1/whoami

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/whoami" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/whoami';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/whoami"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/whoami

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/sites/{site_id}/devices

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/devices" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/devices';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/devices"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/devices

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/kpis

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/kpis" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/kpis';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/kpis"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/kpis

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/period-summary

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/period-summary" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/period-summary';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/period-summary"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/period-summary

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/energy-value

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/energy-value" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/energy-value';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/energy-value"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/energy-value

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/injection-optimality

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/injection-optimality" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/injection-optimality';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/injection-optimality"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/injection-optimality

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/consumption-forecast

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/consumption-forecast" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/consumption-forecast';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/consumption-forecast"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/consumption-forecast

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/energy-series

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/energy-series" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/energy-series';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/energy-series"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/energy-series

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/production-forecast

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/production-forecast" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/production-forecast';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/production-forecast"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/production-forecast

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/production-series

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/production-series" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/production-series';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/production-series"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/production-series

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/weather

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/weather" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/weather';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/weather"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/weather

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/inverter-realtime

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/inverter-realtime" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/inverter-realtime';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/inverter-realtime"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/inverter-realtime

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/diagnostics

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/diagnostics" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/diagnostics';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/diagnostics"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/diagnostics

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/statistics

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/statistics" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/statistics';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/statistics"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/statistics

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/sites/{site_id}/opportunities

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/opportunities" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/opportunities';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/opportunities"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/opportunities

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

GET api/v1/opportunities

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/opportunities" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/opportunities';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/opportunities"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/opportunities

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/sites/{site_id}/discovery-scans/{discoveryScan_id}

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/architecto/discovery-scans/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/discovery-scans/architecto';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/discovery-scans/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/discovery-scans/{discoveryScan_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

discoveryScan_id   string     

The ID of the discoveryScan. Example: architecto

GET api/v1/devices/{device_id}

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/devices/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/devices/architecto';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/devices/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/devices/{device_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

device_id   string     

The ID of the device. Example: architecto

GET api/v1/alarms

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/alarms" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/alarms';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/alarms"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/alarms

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/alert-rules

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/alert-rules" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/alert-rules';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/alert-rules"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/alert-rules

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/alert-rules/{alertRule_id}

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/alert-rules/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/alert-rules/architecto';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/alert-rules/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/alert-rules/{alertRule_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

alertRule_id   string     

The ID of the alertRule. Example: architecto

GET api/v1/edge-installations

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/edge-installations" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge-installations';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge-installations"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/edge-installations

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/edge-installations/{edgeInstallation_id}

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/edge-installations/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge-installations/architecto';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge-installations/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/edge-installations/{edgeInstallation_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

edgeInstallation_id   string     

The ID of the edgeInstallation. Example: architecto

GET api/v1/edge-installations/{edgeInstallation_id}/health-history

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/edge-installations/architecto/health-history" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge-installations/architecto/health-history';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge-installations/architecto/health-history"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/edge-installations/{edgeInstallation_id}/health-history

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

edgeInstallation_id   string     

The ID of the edgeInstallation. Example: architecto

GET api/v1/site-sources

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/site-sources" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/site-sources';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/site-sources"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/site-sources

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

POST api/v1/alert-rules

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/alert-rules" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/alert-rules';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/alert-rules"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST api/v1/alert-rules

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

PATCH api/v1/alert-rules/{alertRule_id}

requires authentication

Example request:
curl --request PATCH \
    "https://sunpilot.cloud/api/v1/alert-rules/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/alert-rules/architecto';
$response = $client->patch(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/alert-rules/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "PATCH",
    headers,
}).then(response => response.json());

Request   

PATCH api/v1/alert-rules/{alertRule_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

alertRule_id   string     

The ID of the alertRule. Example: architecto

DELETE api/v1/alert-rules/{alertRule_id}

requires authentication

Example request:
curl --request DELETE \
    "https://sunpilot.cloud/api/v1/alert-rules/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/alert-rules/architecto';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/alert-rules/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request   

DELETE api/v1/alert-rules/{alertRule_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

alertRule_id   string     

The ID of the alertRule. Example: architecto

POST api/v1/sites/{site_id}/devices

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites/architecto/devices" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"b\",
    \"role\": \"pv_inverter\",
    \"vendor\": \"n\",
    \"model\": \"g\",
    \"capabilities\": [
        \"z\"
    ]
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/devices';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'b',
            'role' => 'pv_inverter',
            'vendor' => 'n',
            'model' => 'g',
            'capabilities' => ['z'],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/devices"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "b",
    "role": "pv_inverter",
    "vendor": "n",
    "model": "g",
    "capabilities": [
        "z"
    ]
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/sites/{site_id}/devices

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

Body Parameters

name   string     

Must not be greater than 255 characters. Example: b

role   string     

Example: pv_inverter

Must be one of:
  • grid_meter
  • pv_inverter
  • battery
  • weather_station
  • ev_charger
  • heat_pump
  • gateway
vendor   string  optional    

Must not be greater than 255 characters. Example: n

model   string  optional    

Must not be greater than 255 characters. Example: g

capabilities   string[]  optional    

Must not be greater than 64 characters.

PATCH api/v1/devices/{device_id}

requires authentication

Example request:
curl --request PATCH \
    "https://sunpilot.cloud/api/v1/devices/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"b\",
    \"offline_after_minutes\": 22,
    \"installed_at\": \"2026-08-01T06:26:43\",
    \"warranty_expires_at\": \"2026-08-01T06:26:43\",
    \"maintenance_interval_months\": 7
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/devices/architecto';
$response = $client->patch(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'b',
            'offline_after_minutes' => 22,
            'installed_at' => '2026-08-01T06:26:43',
            'warranty_expires_at' => '2026-08-01T06:26:43',
            'maintenance_interval_months' => 7,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/devices/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "b",
    "offline_after_minutes": 22,
    "installed_at": "2026-08-01T06:26:43",
    "warranty_expires_at": "2026-08-01T06:26:43",
    "maintenance_interval_months": 7
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

PATCH api/v1/devices/{device_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

device_id   string     

The ID of the device. Example: architecto

Body Parameters

name   string  optional    

Must not be greater than 255 characters. Example: b

offline_after_minutes   integer  optional    

Must be at least 1. Must not be greater than 10080. Example: 22

installed_at   string  optional    

Must be a valid date. Example: 2026-08-01T06:26:43

warranty_expires_at   string  optional    

Must be a valid date. Example: 2026-08-01T06:26:43

maintenance_interval_months   integer  optional    

Must be at least 1. Must not be greater than 120. Example: 7

POST api/v1/devices/{device_id}/maintenance-logs

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/devices/architecto/maintenance-logs" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"performed_at\": \"2026-08-01T06:26:43\",
    \"note\": \"b\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/devices/architecto/maintenance-logs';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'performed_at' => '2026-08-01T06:26:43',
            'note' => 'b',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/devices/architecto/maintenance-logs"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "performed_at": "2026-08-01T06:26:43",
    "note": "b"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/devices/{device_id}/maintenance-logs

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

device_id   string     

The ID of the device. Example: architecto

Body Parameters

performed_at   string  optional    

Must be a valid date. Example: 2026-08-01T06:26:43

note   string  optional    

Must not be greater than 1000 characters. Example: b

PUT api/v1/devices/{device_id}/binding

requires authentication

Example request:
curl --request PUT \
    "https://sunpilot.cloud/api/v1/devices/architecto/binding" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"driver\": \"b\",
    \"driver_version\": \"n\",
    \"config\": {
        \"host\": \"g\"
    },
    \"edge_installation_id\": \"c90237e9-ced5-3af6-88ea-84aeaa148878\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/devices/architecto/binding';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'driver' => 'b',
            'driver_version' => 'n',
            'config' => ['host' => 'g'],
            'edge_installation_id' => 'c90237e9-ced5-3af6-88ea-84aeaa148878',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/devices/architecto/binding"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "driver": "b",
    "driver_version": "n",
    "config": {
        "host": "g"
    },
    "edge_installation_id": "c90237e9-ced5-3af6-88ea-84aeaa148878"
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

PUT api/v1/devices/{device_id}/binding

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

device_id   string     

The ID of the device. Example: architecto

Body Parameters

driver   string     

Must not be greater than 64 characters. Example: b

driver_version   string     

Must not be greater than 32 characters. Example: n

config   object  optional    
host   string  optional    

Must not be greater than 255 characters. Example: g

edge_installation_id   string  optional    

Livello 3 (Edge, ADR-015): quale unità Edge esegue questo driver. Deve appartenere allo stesso site del device, altrimenti 422 — non 404: l'installazione esiste (magari in un altro site dello stesso tenant), il problema è l'associazione, non la risorsa. Must be a valid UUID. Example: c90237e9-ced5-3af6-88ea-84aeaa148878

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites/architecto/cloud-link" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"cloud_connection_id\": \"architecto\",
    \"station_code\": \"n\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/cloud-link';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'cloud_connection_id' => 'architecto',
            'station_code' => 'n',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/cloud-link"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "cloud_connection_id": "architecto",
    "station_code": "n"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

requires authentication

Example request:
curl --request DELETE \
    "https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto/sync" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto/sync';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto/sync"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto/backfill" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto/backfill';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/cloud-links/architecto/backfill"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites/architecto/shelly-link" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"cloud_connection_id\": \"architecto\",
    \"device_id\": \"n\",
    \"name\": \"g\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/shelly-link';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'cloud_connection_id' => 'architecto',
            'device_id' => 'n',
            'name' => 'g',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/shelly-link"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "cloud_connection_id": "architecto",
    "device_id": "n",
    "name": "g"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

POST api/v1/sites/{site_id}/discovery-scans

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites/architecto/discovery-scans" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"host\": \"b\",
    \"port\": 22,
    \"unit_id_start\": 7,
    \"unit_id_end\": 16
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/discovery-scans';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'host' => 'b',
            'port' => 22,
            'unit_id_start' => 7,
            'unit_id_end' => 16,
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/discovery-scans"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "host": "b",
    "port": 22,
    "unit_id_start": 7,
    "unit_id_end": 16
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/sites/{site_id}/discovery-scans

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

Body Parameters

host   string     

Must not be greater than 255 characters. Example: b

port   integer  optional    

Must be at least 1. Must not be greater than 65535. Example: 22

unit_id_start   integer  optional    

Must be at least 1. Must not be greater than 247. Example: 7

unit_id_end   integer  optional    

Must be at least 1. Must not be greater than 247. Example: 16

POST api/v1/edge-installations

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/edge-installations" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"site_id\": \"6ff8f7f6-1eb3-3525-be4a-3932c805afed\",
    \"label\": \"g\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge-installations';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'site_id' => '6ff8f7f6-1eb3-3525-be4a-3932c805afed',
            'label' => 'g',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge-installations"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "site_id": "6ff8f7f6-1eb3-3525-be4a-3932c805afed",
    "label": "g"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/edge-installations

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

site_id   string     

Must be a valid UUID. Must match an existing stored value. Example: 6ff8f7f6-1eb3-3525-be4a-3932c805afed

label   string  optional    

Must not be greater than 255 characters. Example: g

POST api/v1/edge-installations/{edgeInstallation_id}/rotate-code

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/edge-installations/architecto/rotate-code" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge-installations/architecto/rotate-code';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge-installations/architecto/rotate-code"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST api/v1/edge-installations/{edgeInstallation_id}/rotate-code

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

edgeInstallation_id   string     

The ID of the edgeInstallation. Example: architecto

DELETE api/v1/edge-installations/{edgeInstallation_id}

requires authentication

Example request:
curl --request DELETE \
    "https://sunpilot.cloud/api/v1/edge-installations/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/edge-installations/architecto';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/edge-installations/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request   

DELETE api/v1/edge-installations/{edgeInstallation_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

edgeInstallation_id   string     

The ID of the edgeInstallation. Example: architecto

PATCH api/v1/opportunities/{siteOpportunity_id}

requires authentication

Example request:
curl --request PATCH \
    "https://sunpilot.cloud/api/v1/opportunities/architecto" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"status\": \"new\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/opportunities/architecto';
$response = $client->patch(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'status' => 'new',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/opportunities/architecto"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "status": "new"
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

PATCH api/v1/opportunities/{siteOpportunity_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

siteOpportunity_id   string     

The ID of the siteOpportunity. Example: architecto

Body Parameters

status   string     

Example: new

Must be one of:
  • new
  • reviewed
  • dismissed
  • won

POST api/v1/sites/{site_id}/diagnostics/findings/{key}/review

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites/architecto/diagnostics/findings/architecto/review" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/diagnostics/findings/architecto/review';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/diagnostics/findings/architecto/review"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST api/v1/sites/{site_id}/diagnostics/findings/{key}/review

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

key   string     

Example: architecto

DELETE api/v1/sites/{site_id}/diagnostics/findings/{key}/review

requires authentication

Example request:
curl --request DELETE \
    "https://sunpilot.cloud/api/v1/sites/architecto/diagnostics/findings/architecto/review" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/architecto/diagnostics/findings/architecto/review';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/architecto/diagnostics/findings/architecto/review"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Request   

DELETE api/v1/sites/{site_id}/diagnostics/findings/{key}/review

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   string     

The ID of the site. Example: architecto

key   string     

Example: architecto

GET api/v1/admin/projects

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/admin/projects" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/projects';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/projects"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/admin/projects

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/admin/projects/{tenant_id}

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/admin/projects/019f6ec9-fdf5-73dd-8605-b3741d429264" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/projects/019f6ec9-fdf5-73dd-8605-b3741d429264';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/projects/019f6ec9-fdf5-73dd-8605-b3741d429264"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/admin/projects/{tenant_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

PUT api/v1/admin/projects/{tenant_id}/note

requires authentication

Example request:
curl --request PUT \
    "https://sunpilot.cloud/api/v1/admin/projects/019f6ec9-fdf5-73dd-8605-b3741d429264/note" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"status\": \"suspended\",
    \"contact_name\": \"b\",
    \"contact_email\": \"zbailey@example.net\",
    \"started_at\": \"2026-08-01T06:26:43\",
    \"notes_md\": \"architecto\",
    \"checklist\": [
        {
            \"label\": \"n\",
            \"done\": false
        }
    ]
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/projects/019f6ec9-fdf5-73dd-8605-b3741d429264/note';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'status' => 'suspended',
            'contact_name' => 'b',
            'contact_email' => 'zbailey@example.net',
            'started_at' => '2026-08-01T06:26:43',
            'notes_md' => 'architecto',
            'checklist' => [
                ['label' => 'n', 'done' => false],
            ],
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/projects/019f6ec9-fdf5-73dd-8605-b3741d429264/note"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "status": "suspended",
    "contact_name": "b",
    "contact_email": "zbailey@example.net",
    "started_at": "2026-08-01T06:26:43",
    "notes_md": "architecto",
    "checklist": [
        {
            "label": "n",
            "done": false
        }
    ]
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

PUT api/v1/admin/projects/{tenant_id}/note

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

Body Parameters

status   string     

Example: suspended

Must be one of:
  • onboarding
  • active
  • suspended
  • archived
contact_name   string  optional    

Must not be greater than 255 characters. Example: b

contact_email   string  optional    

Must be a valid email address. Must not be greater than 255 characters. Example: zbailey@example.net

started_at   string  optional    

Must be a valid date. Example: 2026-08-01T06:26:43

notes_md   string  optional    

Example: architecto

checklist   object[]  optional    
label   string  optional    

This field is required when checklist is present. Must not be greater than 255 characters. Example: n

done   boolean  optional    

This field is required when checklist is present. Example: false

GET api/v1/admin/docs

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/admin/docs" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/docs';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/docs"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/admin/docs

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/admin/docs/content

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/admin/docs/content" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/docs/content';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/docs/content"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/admin/docs/content

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

GET api/v1/admin/tenants

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/admin/tenants" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/admin/tenants

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

POST api/v1/admin/tenants

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/admin/tenants" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"type\": \"individual\",
    \"name\": \"b\",
    \"slug\": \"n\",
    \"owner_email\": \"ashly64@example.com\",
    \"legal_name\": \"v\",
    \"vat_number\": \"d\",
    \"billing_email\": \"jermaine.tillman@example.org\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'type' => 'individual',
            'name' => 'b',
            'slug' => 'n',
            'owner_email' => 'ashly64@example.com',
            'legal_name' => 'v',
            'vat_number' => 'd',
            'billing_email' => 'jermaine.tillman@example.org',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "type": "individual",
    "name": "b",
    "slug": "n",
    "owner_email": "ashly64@example.com",
    "legal_name": "v",
    "vat_number": "d",
    "billing_email": "jermaine.tillman@example.org"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/admin/tenants

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

type   string     

Example: individual

Must be one of:
  • individual
  • organization
name   string     

Must not be greater than 255 characters. Example: b

slug   string     

Must not be greater than 255 characters. Example: n

owner_email   string     

Must be a valid email address. Must not be greater than 255 characters. Example: ashly64@example.com

legal_name   string  optional    

Must not be greater than 255 characters. Example: v

vat_number   string  optional    

Must not be greater than 255 characters. Example: d

billing_email   string  optional    

Must be a valid email address. Must not be greater than 255 characters. Example: jermaine.tillman@example.org

GET api/v1/admin/tenants/{tenant_id}

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/admin/tenants/{tenant_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

PUT api/v1/admin/tenants/{tenant_id}

requires authentication

Example request:
curl --request PUT \
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"b\",
    \"slug\": \"n\",
    \"legal_name\": \"g\",
    \"vat_number\": \"z\",
    \"billing_email\": \"rempel.chadrick@example.org\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'b',
            'slug' => 'n',
            'legal_name' => 'g',
            'vat_number' => 'z',
            'billing_email' => 'rempel.chadrick@example.org',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "b",
    "slug": "n",
    "legal_name": "g",
    "vat_number": "z",
    "billing_email": "rempel.chadrick@example.org"
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

PUT api/v1/admin/tenants/{tenant_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

Body Parameters

name   string  optional    

Must not be greater than 255 characters. Example: b

slug   string  optional    

Must not be greater than 255 characters. Example: n

legal_name   string  optional    

Must not be greater than 255 characters. Example: g

vat_number   string  optional    

Must not be greater than 255 characters. Example: z

billing_email   string  optional    

Must be a valid email address. Must not be greater than 255 characters. Example: rempel.chadrick@example.org

POST api/v1/admin/tenants/{tenant_id}/suspend

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/suspend" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"reason\": \"b\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/suspend';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'reason' => 'b',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/suspend"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "reason": "b"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

POST api/v1/admin/tenants/{tenant_id}/suspend

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

Body Parameters

reason   string     

Must not be greater than 500 characters. Example: b

POST api/v1/admin/tenants/{tenant_id}/unsuspend

requires authentication

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/unsuspend" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/unsuspend';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/unsuspend"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "POST",
    headers,
}).then(response => response.json());

Request   

POST api/v1/admin/tenants/{tenant_id}/unsuspend

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

GET api/v1/admin/tenants/{tenant_id}/subscription

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/subscription" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/subscription';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/subscription"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/admin/tenants/{tenant_id}/subscription

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

PUT api/v1/admin/tenants/{tenant_id}/plan

requires authentication

Example request:
curl --request PUT \
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/plan" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"plan_slug\": \"b\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/plan';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'plan_slug' => 'b',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/plan"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "plan_slug": "b"
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

PUT api/v1/admin/tenants/{tenant_id}/plan

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

Body Parameters

plan_slug   string     

Must not be greater than 50 characters. Example: b

PUT api/v1/admin/tenants/{tenant_id}/trial

requires authentication

Example request:
curl --request PUT \
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/trial" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"trial_ends_at\": \"2026-08-01T06:26:43\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/trial';
$response = $client->put(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'trial_ends_at' => '2026-08-01T06:26:43',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/tenants/019f6ec9-fdf5-73dd-8605-b3741d429264/trial"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "trial_ends_at": "2026-08-01T06:26:43"
};

fetch(url, {
    method: "PUT",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Request   

PUT api/v1/admin/tenants/{tenant_id}/trial

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

tenant_id   string     

The ID of the tenant. Example: 019f6ec9-fdf5-73dd-8605-b3741d429264

Body Parameters

trial_ends_at   string  optional    

Must be a valid date. Example: 2026-08-01T06:26:43

GET api/v1/admin/audit

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/admin/audit" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/admin/audit';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/admin/audit"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/admin/audit

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Identità

Chi sono

requires authentication

Restituisce l'utente autenticato, il tenant in cui opera il token e il suo ruolo. Utile come primo endpoint di verifica dopo aver ottenuto un access token.

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/me" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/me';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/me"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "user": {
        "id": 1,
        "name": "Mario Rossi",
        "email": "mario@installatore.it"
    },
    "tenant": {
        "id": 1
    },
    "role": "owner"
}
 

Request   

GET api/v1/me

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Impianti

Gli impianti (sites) sono l'anagrafica di base: ogni device, misura e KPI appartiene a un impianto del tuo tenant.

Elenca gli impianti

requires authentication

Impianti del tenant, paginati, con stato di collegamento cloud e ultima misura.

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites?per_page=25" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'per_page' => '25',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites"
);

const params = {
    "per_page": "25",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "id": 1,
            "name": "Capannone Rossi",
            "timezone": "Europe/Rome",
            "cloud_connected": true,
            "cloud_links": [
                {
                    "id": "0198f2b0-1a2b-73e0-8b1c-8f6c2e2b9a10",
                    "provider": "fusionsolar",
                    "label": null,
                    "station_code": "NE=12345678",
                    "last_synced_at": "2026-07-09T11:45:00.000000Z",
                    "backfill_status": null,
                    "backfill_result": null,
                    "backfill_error": null
                }
            ],
            "online": true,
            "last_seen_at": "2026-07-09T11:45:12.000000Z",
            "last_measurement_at": "2026-07-09T11:00:00.000000Z",
            "latitude": 45.4642,
            "longitude": 9.19,
            "address": "Via Baldini 12, Milano",
            "peak_power_kwp": 60,
            "tilt": 10,
            "azimuth": 0,
            "has_pv_geometry": true,
            "diagnostics_severity": null,
            "diagnostics_computed_at": null
        }
    ],
    "links": {
        "first": "https://sunpilot.cloud/api/v1/sites?page=1",
        "last": "https://sunpilot.cloud/api/v1/sites?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "per_page": 25,
        "total": 1
    }
}
 

Request   

GET api/v1/sites

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

per_page   integer  optional    

Risultati per pagina (1–1000). Default: 15. Example: 25

Dettaglio impianto

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/1" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/1';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/1"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "id": 1,
        "name": "Capannone Rossi",
        "timezone": "Europe/Rome",
        "cloud_connected": true,
        "cloud_links": [
            {
                "id": "0198f2b0-1a2b-73e0-8b1c-8f6c2e2b9a10",
                "provider": "fusionsolar",
                "label": null,
                "station_code": "NE=12345678",
                "last_synced_at": "2026-07-09T11:45:00.000000Z",
                "backfill_status": null,
                "backfill_result": null,
                "backfill_error": null
            }
        ],
        "online": true,
        "last_seen_at": "2026-07-09T11:45:12.000000Z",
        "last_measurement_at": "2026-07-09T11:00:00.000000Z",
        "latitude": 45.4642,
        "longitude": 9.19,
        "address": "Via Baldini 12, Milano",
        "peak_power_kwp": 60,
        "tilt": 10,
        "azimuth": 0,
        "has_pv_geometry": true,
        "diagnostics_severity": null,
        "diagnostics_computed_at": null
    }
}
 

Example response (404):


{
    "message": "Not found."
}
 

Request   

GET api/v1/sites/{site_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   integer     

ID dell'impianto. Example: 1

Dettaglio impianto (aggregato)

requires authentication

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/sites/1/detail" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/1/detail';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/1/detail"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Request   

GET api/v1/sites/{site_id}/detail

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   integer     

ID dell'impianto. Example: 1

Cerca un indirizzo

requires authentication

Proxy verso Google Maps Geocoding API per popolare automaticamente latitudine/longitudine dell'impianto a partire da un indirizzo testuale.

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/geocode?q=Via+Baldini%2C+Milano" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/geocode';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'q' => 'Via Baldini, Milano',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/geocode"
);

const params = {
    "q": "Via Baldini, Milano",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "display_name": "Via Baldini, Milano, MI, Italia",
            "latitude": 45.4642,
            "longitude": 9.19
        }
    ]
}
 

Request   

GET api/v1/geocode

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

q   string     

Indirizzo o parte di esso da cercare. Example: Via Baldini, Milano

Rileva geometria tetto

requires authentication

Proxy verso Google Solar API (Building Insights): rileva tilt/azimuth della falda principale del tetto da lat/lng, per precompilare il form di geometria impianto senza inserimento manuale.

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/roof-detect?lat=45.4642&lng=9.19" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/roof-detect';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'lat' => '45.4642',
            'lng' => '9.19',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/roof-detect"
);

const params = {
    "lat": "45.4642",
    "lng": "9.19",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": {
        "tilt": 28,
        "azimuth": 10,
        "area_m2": 50
    }
}
 

Request   

GET api/v1/roof-detect

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Query Parameters

lat   number     

Latitudine. Example: 45.4642

lng   number     

Longitudine. Example: 9.19

Crea un impianto

requires authentication

Richiede scope write e un ruolo abilitato alla scrittura. Se il piano del tenant ha raggiunto il limite di impianti risponde 402 con error: plan_limit.

Example request:
curl --request POST \
    "https://sunpilot.cloud/api/v1/sites" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Capannone Rossi\",
    \"timezone\": \"Europe\\/Rome\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites';
$response = $client->post(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'Capannone Rossi',
            'timezone' => 'Europe/Rome',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Capannone Rossi",
    "timezone": "Europe\/Rome"
};

fetch(url, {
    method: "POST",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (201):


{
    "data": {
        "id": 2,
        "name": "Capannone Rossi",
        "timezone": "Europe/Rome",
        "cloud_connected": false,
        "cloud_links": [],
        "online": false,
        "last_seen_at": null,
        "last_measurement_at": null,
        "latitude": null,
        "longitude": null,
        "address": null,
        "peak_power_kwp": null,
        "tilt": null,
        "azimuth": null,
        "has_pv_geometry": false
    }
}
 

Example response (402):


{
    "error": "plan_limit",
    "message": "Hai raggiunto il limite di impianti del piano Free. Passa a un piano superiore per aggiungerne altri."
}
 

Request   

POST api/v1/sites

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

Body Parameters

name   string     

Nome dell'impianto. Example: Capannone Rossi

timezone   string  optional    

Timezone IANA. Default: Europe/Rome se omesso — il client dovrebbe passare il fuso rilevato lato browser. Example: Europe/Rome

Aggiorna un impianto

requires authentication

Anagrafica e geometria FV (latitudine/longitudine, potenza di picco, tilt, azimuth) usata per la previsione di produzione PVGIS.

Example request:
curl --request PATCH \
    "https://sunpilot.cloud/api/v1/sites/1" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json" \
    --data "{
    \"name\": \"Capannone Rossi\",
    \"timezone\": \"Europe\\/Rome\",
    \"latitude\": 45.4642,
    \"longitude\": 9.19,
    \"address\": \"Via Baldini 12, Milano\",
    \"peak_power_kwp\": 60,
    \"tilt\": 10,
    \"azimuth\": 0,
    \"energy_price_eur_kwh\": 0.25,
    \"grid_power_limit_kw\": 6,
    \"annual_consumption_kwh\": 19,
    \"supply_pod\": \"IT001E12345678\",
    \"supply_distributor\": \"e-distribuzione\",
    \"supply_activation_date\": \"2024-03-01\",
    \"supply_contact_name\": \"Mario Rossi\",
    \"supply_contact_phone\": \"+39 333 1234567\",
    \"supply_contact_email\": \"mario.rossi@example.com\"
}"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/1';
$response = $client->patch(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'json' => [
            'name' => 'Capannone Rossi',
            'timezone' => 'Europe/Rome',
            'latitude' => 45.4642,
            'longitude' => 9.19,
            'address' => 'Via Baldini 12, Milano',
            'peak_power_kwp' => 60.0,
            'tilt' => 10,
            'azimuth' => 0,
            'energy_price_eur_kwh' => 0.25,
            'grid_power_limit_kw' => 6.0,
            'annual_consumption_kwh' => 19,
            'supply_pod' => 'IT001E12345678',
            'supply_distributor' => 'e-distribuzione',
            'supply_activation_date' => '2024-03-01',
            'supply_contact_name' => 'Mario Rossi',
            'supply_contact_phone' => '+39 333 1234567',
            'supply_contact_email' => 'mario.rossi@example.com',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/1"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};

let body = {
    "name": "Capannone Rossi",
    "timezone": "Europe\/Rome",
    "latitude": 45.4642,
    "longitude": 9.19,
    "address": "Via Baldini 12, Milano",
    "peak_power_kwp": 60,
    "tilt": 10,
    "azimuth": 0,
    "energy_price_eur_kwh": 0.25,
    "grid_power_limit_kw": 6,
    "annual_consumption_kwh": 19,
    "supply_pod": "IT001E12345678",
    "supply_distributor": "e-distribuzione",
    "supply_activation_date": "2024-03-01",
    "supply_contact_name": "Mario Rossi",
    "supply_contact_phone": "+39 333 1234567",
    "supply_contact_email": "mario.rossi@example.com"
};

fetch(url, {
    method: "PATCH",
    headers,
    body: JSON.stringify(body),
}).then(response => response.json());

Example response (200):


{
    "data": {
        "id": 1,
        "name": "Capannone Rossi",
        "timezone": "Europe/Rome",
        "cloud_connected": true,
        "cloud_links": [
            {
                "id": "0198f2b0-1a2b-73e0-8b1c-8f6c2e2b9a10",
                "provider": "fusionsolar",
                "label": null,
                "station_code": "NE=12345678",
                "last_synced_at": "2026-07-09T11:45:00.000000Z",
                "backfill_status": null,
                "backfill_result": null,
                "backfill_error": null
            }
        ],
        "online": true,
        "last_seen_at": "2026-07-09T11:45:12.000000Z",
        "last_measurement_at": "2026-07-09T11:00:00.000000Z",
        "latitude": 45.4642,
        "longitude": 9.19,
        "address": "Via Baldini 12, Milano",
        "peak_power_kwp": 60,
        "tilt": 10,
        "azimuth": 0,
        "has_pv_geometry": true
    }
}
 

Request   

PATCH api/v1/sites/{site_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   integer     

ID dell'impianto. Example: 1

Body Parameters

name   string  optional    

Nome. Example: Capannone Rossi

timezone   string  optional    

Timezone IANA. Example: Europe/Rome

latitude   number  optional    

Latitudine (-90–90). Example: 45.4642

longitude   number  optional    

Longitudine (-180–180). Example: 9.19

address   string  optional    

Indirizzo testuale (compilato dalla ricerca indirizzo). Example: Via Baldini 12, Milano

peak_power_kwp   number  optional    

Potenza di picco in kWp. Example: 60

tilt   integer  optional    

Inclinazione moduli in gradi (0–90). Example: 10

azimuth   integer  optional    

Azimut in gradi (-180–180, 0 = sud). Example: 0

energy_price_eur_kwh   number  optional    

Prezzo energia €/kWh per la valorizzazione. Example: 0.25

grid_power_limit_kw   number  optional    

Potenza contrattuale del punto di connessione in kW. Example: 6

annual_consumption_kwh   number  optional    

Must be at least 0. Must not be greater than 1000000. Example: 19

supply_pod   string  optional    

Codice POD del punto di connessione (formato italiano IT + 3 cifre + E/G + 8 cifre). Example: IT001E12345678

supply_distributor   string  optional    

Nome del distributore locale (DSO). Example: e-distribuzione

supply_activation_date   string  optional    

Data di attivazione della fornitura (YYYY-MM-DD), non futura. Example: 2024-03-01

supply_contact_name   string  optional    

Nome del referente per la fornitura. Example: Mario Rossi

supply_contact_phone   string  optional    

Telefono del referente. Example: +39 333 1234567

supply_contact_email   string  optional    

Email del referente. Example: mario.rossi@example.com

Elimina un impianto

requires authentication

Elimina l'impianto e, a cascata, i suoi device, misure e binding. Irreversibile.

Example request:
curl --request DELETE \
    "https://sunpilot.cloud/api/v1/sites/1" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/sites/1';
$response = $client->delete(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/sites/1"
);

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "DELETE",
    headers,
}).then(response => response.json());

Example response (204):

Empty response
 

Request   

DELETE api/v1/sites/{site_id}

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

site_id   integer     

ID dell'impianto. Example: 1

Telemetria

Misure di un device

requires authentication

Serie temporale delle misure canoniche di un device, dalla più recente. Ogni misura è la "scheda di lettura" SunPilot: metrica, valore, unità, fase, qualità, timestamp UTC — identica per qualunque vendor.

Example request:
curl --request GET \
    --get "https://sunpilot.cloud/api/v1/devices/1/measurements?metric=pv_production_power&phase=total&from=2026-07-08T00%3A00%3A00Z&to=2026-07-09T00%3A00%3A00Z&per_page=100" \
    --header "Authorization: Bearer {ACCESS_TOKEN}" \
    --header "Content-Type: application/json" \
    --header "Accept: application/json"
$client = new \GuzzleHttp\Client();
$url = 'https://sunpilot.cloud/api/v1/devices/1/measurements';
$response = $client->get(
    $url,
    [
        'headers' => [
            'Authorization' => 'Bearer {ACCESS_TOKEN}',
            'Content-Type' => 'application/json',
            'Accept' => 'application/json',
        ],
        'query' => [
            'metric' => 'pv_production_power',
            'phase' => 'total',
            'from' => '2026-07-08T00:00:00Z',
            'to' => '2026-07-09T00:00:00Z',
            'per_page' => '100',
        ],
    ]
);
$body = $response->getBody();
print_r(json_decode((string) $body));
const url = new URL(
    "https://sunpilot.cloud/api/v1/devices/1/measurements"
);

const params = {
    "metric": "pv_production_power",
    "phase": "total",
    "from": "2026-07-08T00:00:00Z",
    "to": "2026-07-09T00:00:00Z",
    "per_page": "100",
};
Object.keys(params)
    .forEach(key => url.searchParams.append(key, params[key]));

const headers = {
    "Authorization": "Bearer {ACCESS_TOKEN}",
    "Content-Type": "application/json",
    "Accept": "application/json",
};


fetch(url, {
    method: "GET",
    headers,
}).then(response => response.json());

Example response (200):


{
    "data": [
        {
            "metric": "pv_production_power",
            "value": 41800,
            "unit": "W",
            "sampling": "instantaneous",
            "phase": "total",
            "quality": "measured",
            "timestamp_utc": "2026-07-09T11:00:00.000000Z",
            "source_driver": "fusionsolar"
        }
    ],
    "links": {
        "first": "https://sunpilot.cloud/api/v1/devices/1/measurements?page=1",
        "last": "https://sunpilot.cloud/api/v1/devices/1/measurements?page=1",
        "prev": null,
        "next": null
    },
    "meta": {
        "current_page": 1,
        "per_page": 50,
        "total": 1
    }
}
 

Request   

GET api/v1/devices/{device_id}/measurements

Headers

Authorization        

Example: Bearer {ACCESS_TOKEN}

Content-Type        

Example: application/json

Accept        

Example: application/json

URL Parameters

device_id   integer     

ID del device. Example: 1

Query Parameters

metric   string  optional    

Filtra per metrica canonica, snake_case (es. pv_production_power, grid_import_power, load_consumption_power, battery_state_of_charge, voltage, irradiance). Example: pv_production_power

phase   string  optional    

Fase: total, l1, l2, l3. Example: total

from   string  optional    

Da (data/ora ISO 8601). Example: 2026-07-08T00:00:00Z

to   string  optional    

A (data/ora ISO 8601). Example: 2026-07-09T00:00:00Z

per_page   integer  optional    

Risultati per pagina (1–200). Default: 50. Example: 100