{"openapi":"3.1.0","info":{"title":"Wolta API","description":"Elprisdata, optimeringsbetyg och lönsamhetskalkyl för sol och batteri.\n\nFritt för privat bruk. Rådata om elpriser och stödtjänster vidareförmedlar Svenska kraftnäts material under CC BY 4.0 (arkivet t.o.m. 2026-07-01 för SE1-SE4 och grannzonerna, systempriset, aFRR, mFRR och FCR t.o.m. 2026-04-14) och den datan får användas fritt även kommersiellt, med attribution. FCR-kapaciteten därefter kommer från Svenska kraftnäts Mimer, som inte anger några villkor för vidareutnyttjande. Priser efter 2026-07-01 - för SE1-SE4 via elprisetjustnu.se - och för övriga europeiska elområden kommer från ENTSO-E Transparency Platform under ENTSO-E:s villkor, inte CC BY. Svarsfältet `source` anger källan per svar. Woltas egna beräkningar (optimeringsbetyg, lönsamhetskalkyl, dimensionering) kräver avtal för kommersiell användning: kontakt@wolta.se. Villkor: https://wolta.se/villkor\n\nFelmeddelandena i svarens `detail` är på svenska. Förgrena på statuskoden, och på `detail.error` där den finns, aldrig på meddelandetexten.","termsOfService":"https://wolta.se/villkor","contact":{"name":"Wolta","url":"https://wolta.se/api","email":"kontakt@wolta.se"},"version":"0.97.0"},"servers":[{"url":"https://wolta.se","description":"Production"}],"paths":{"/api/v1/health":{"get":{"tags":["drift"],"summary":"Hälsokontroll","description":"Svarar `{\"status\": \"ok\"}` när API:t är uppe, plus en konfigurationsbit som visar att saltet för anläggningsidentiteter är satt. För övervakning.","operationId":"health_api_v1_health_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Health Api V1 Health Get"}}}}}}},"/api/v1/prices/now":{"get":{"tags":["priser"],"summary":"Pris just nu","description":"Spotpriset för innevarande timme plus hela dagens och morgondagens serie för en zon. Priser anges i öre/kWh exklusive moms; svaret bär `vat_factor` för den som vill visa inklusive moms. Morgondagens serie finns först sedan day-ahead-priserna publicerats (Wolta hämtar dem från 13:15 svensk tid).","operationId":"prices_now_api_v1_prices_now_get","parameters":[{"name":"zone","in":"query","required":true,"schema":{"type":"string","title":"Zone"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Prices Now Api V1 Prices Now Get"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/prices":{"get":{"tags":["priser"],"summary":"Historiska priser","description":"Prishistorik för en zon mellan två datum.\n\n- `resolution=15m` ger nativa rader: timvärden före 2025-10-01, kvartsvärden efter.\n- `resolution=1h` ger timmedel, `1d`/`1mo` aggregat per kalenderdygn respektive månad. Medlen viktas med tid: ett kvartsdygn väger lika mycket som ett timdygn.\n- `unit=ore` räknar om till öre/kWh via Riksbankens växelkurs (`v` är null när kurs saknas för dygnet); `1d`/`1mo` med `unit=ore` returnerar endast medelvärdet.\n- `vat=true` (×1,25) kräver `unit=ore`.\n\n`15m` och `1h` tar högst 400 dagar per anrop.","operationId":"prices_api_v1_prices_get","parameters":[{"name":"zone","in":"query","required":true,"schema":{"type":"string","title":"Zone"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date","title":"From"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date","title":"To"}},{"name":"resolution","in":"query","required":false,"schema":{"enum":["15m","1h","1d","1mo"],"type":"string","default":"1h","title":"Resolution"}},{"name":"unit","in":"query","required":false,"schema":{"enum":["eur","ore"],"type":"string","default":"eur","title":"Unit"}},{"name":"vat","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Vat"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Prices Api V1 Prices Get"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stats/compare":{"get":{"tags":["priser"],"summary":"Jämför två perioder","description":"Ställer två godtyckliga perioder mot varandra för en zon, till exempel juni i år mot juni för tre år sedan. Båda perioderna anges med `from` före `to`, annars 422. Medlen viktas med tid: ett kvartsdygn väger lika mycket som ett timdygn.","operationId":"compare_api_v1_stats_compare_get","parameters":[{"name":"zone","in":"query","required":true,"schema":{"type":"string","title":"Zone"}},{"name":"a_from","in":"query","required":true,"schema":{"type":"string","format":"date","title":"A From"}},{"name":"a_to","in":"query","required":true,"schema":{"type":"string","format":"date","title":"A To"}},{"name":"b_from","in":"query","required":true,"schema":{"type":"string","format":"date","title":"B From"}},{"name":"b_to","in":"query","required":true,"schema":{"type":"string","format":"date","title":"B To"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Compare Api V1 Stats Compare Get"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/stats/records":{"get":{"tags":["priser"],"summary":"Pristoppar och prisbottnar","description":"De fem dyraste och fem billigaste timmarna och dygnen för en zon. 404 om zonen saknar prisdata.","operationId":"records_api_v1_stats_records_get","parameters":[{"name":"zone","in":"query","required":true,"schema":{"type":"string","title":"Zone"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Records Api V1 Stats Records Get"}}}},"404":{"description":"Ingen data för den efterfrågade zonen eller marknaden."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/control-systems":{"get":{"tags":["anläggning"],"summary":"Styrsystem","description":"Listar de styrsystem en anläggning kan ange, i visningsordning, med etikett och de Home Assistant-integrationsdomäner som brukar betyda just det systemet. `ha_domains` är ett förslag för förifyllning – användaren bekräftar alltid. Svaret är publikt och cachebart ett dygn.","operationId":"list_control_systems_api_v1_control_systems_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response List Control Systems Api V1 Control Systems Get"}}}}}}},"/api/v1/ancillary/{market}":{"get":{"tags":["priser"],"summary":"Stödtjänstmarknader","description":"Kapacitetspriser (EUR/MW) och aktiverad energi (EUR/MWh) per zon och riktning för `afrr`, `mfrr` eller `fcr`. Högst 400 dagar per anrop. Okänd marknad ger 404. aFRR och mFRR: SVK:s öppna data (CC BY 4.0). FCR: SVK:s öppna data t.o.m. 2026-04-14, därefter Mimer (inga publicerade villkor). Fältet `source` anger källan för svarets fönster.","operationId":"ancillary_api_v1_ancillary__market__get","parameters":[{"name":"market","in":"path","required":true,"schema":{"type":"string","title":"Market"}},{"name":"zone","in":"query","required":true,"schema":{"type":"string","title":"Zone"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date","title":"From"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date","title":"To"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Ancillary Api V1 Ancillary  Market  Get"}}}},"404":{"description":"Ingen data för den efterfrågade zonen eller marknaden."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/quality":{"get":{"tags":["priser"],"summary":"Datakvalitet och källor","description":"Hur prisdatan är sammansatt: källfördelning per zon (Svenska kraftnät, elprisetjustnu.se, ENTSO-E eller interpolerad), täckningsperiod per zon och de senaste ingest-körningarna. Använd den för att bedöma hur komplett underlaget är innan ni bygger vidare på det.","operationId":"quality_api_v1_quality_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Quality Api V1 Quality Get"}}}}}}},"/api/v1/simulate/battery":{"get":{"tags":["betyg"],"summary":"Arbitragesimulering mot historiska priser","description":"Simulerar vad ett batteri hade tjänat på faktiska spotpriser från 2020 och framåt, med en linjäroptimering per dygn. Ger den teoretiska övre gränsen som ett verkligt betyg jämförs mot.","operationId":"simulate_battery_api_v1_simulate_battery_get","parameters":[{"name":"zone","in":"query","required":true,"schema":{"type":"string","title":"Zone"}},{"name":"kwh","in":"query","required":true,"schema":{"type":"number","maximum":10000,"exclusiveMinimum":0,"title":"Kwh"}},{"name":"kw","in":"query","required":true,"schema":{"type":"number","maximum":10000,"exclusiveMinimum":0,"title":"Kw"}},{"name":"eff","in":"query","required":false,"schema":{"type":"number","maximum":1,"exclusiveMinimum":0.3,"default":0.9,"title":"Eff"}},{"name":"factor","in":"query","required":false,"schema":{"type":"number","maximum":1,"exclusiveMinimum":0,"default":0.36,"title":"Factor"}},{"name":"cost","in":"query","required":false,"schema":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Cost"}},{"name":"cycles","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":10,"exclusiveMinimum":0},{"type":"null"}],"title":"Cycles"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Simulate Battery Api V1 Simulate Battery Get"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/simulate/household":{"get":{"tags":["anläggning"],"summary":"Hushållsekonomi för sol och batteri","description":"Räknar IRR, payback och en värdeuppdelning för sol och batteri. `mode=decision` svarar på om en investering lönar sig, `mode=history` på vad en redan gjord investering gett. `future_price_factor` skalar den framtida prisnivån i projektionen (scenarierna Låg, Mellan och Hög).\n\nVarm cache svarar 200 direkt; kall väg svarar 202 med `warm.config_key` som pollas via `GET /warm/by-config`, varefter anropet görs om. Anläggningens profil-token skickas i `Authorization: Bearer`; frågeparametern `profile_token` finns kvar som föråldrad fallback för redan utlevererade webbklienter.\n\nI `mode=history` bär svaret dessutom ett `realized`-block: `irr` beräknad på en daterad kassaflödesserie (capex på etappernas egna datum, faktiska årsbesparingar, framskrivning till `horizon_end` – en fast 30-årshorisont från det första köpet), `irr_status` (`ok`, `ambiguous` vid flera matematiska rötter, `insufficient` under ett års data, `none` utan lösning) och `capex_events`. Break-even (`breakeven_date`/`breakeven_total_years`) är seriens SISTA nollgenomgång, inte den första.","operationId":"simulate_household_api_v1_simulate_household_get","parameters":[{"name":"zone","in":"query","required":true,"schema":{"type":"string","title":"Zone"}},{"name":"mode","in":"query","required":true,"schema":{"type":"string","title":"Mode"}},{"name":"pv_kwp","in":"query","required":false,"schema":{"type":"number","maximum":500,"exclusiveMinimum":0,"default":10,"title":"Pv Kwp"}},{"name":"load_annual","in":"query","required":false,"schema":{"type":"number","maximum":200000,"exclusiveMinimum":0,"default":20000,"title":"Load Annual"}},{"name":"has_battery","in":"query","required":false,"schema":{"type":"boolean","default":true,"title":"Has Battery"}},{"name":"kwh","in":"query","required":false,"schema":{"type":"number","maximum":10000,"exclusiveMinimum":0,"default":10,"title":"Kwh"}},{"name":"kw","in":"query","required":false,"schema":{"type":"number","maximum":10000,"exclusiveMinimum":0,"default":5,"title":"Kw"}},{"name":"eff","in":"query","required":false,"schema":{"type":"number","maximum":1,"exclusiveMinimum":0.3,"default":0.9,"title":"Eff"}},{"name":"realism_factor","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":1,"exclusiveMinimum":0},{"type":"null"}],"title":"Realism Factor"}},{"name":"selfuse_capture","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":1,"exclusiveMinimum":0},{"type":"null"}],"title":"Selfuse Capture"}},{"name":"solar_export_capture","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":1,"exclusiveMinimum":0},{"type":"null"}],"title":"Solar Export Capture"}},{"name":"capex_battery","in":"query","required":false,"schema":{"type":"number","minimum":0,"default":0,"title":"Capex Battery"}},{"name":"capex_solar","in":"query","required":false,"schema":{"type":"number","minimum":0,"default":0,"title":"Capex Solar"}},{"name":"persons","in":"query","required":false,"schema":{"type":"integer","maximum":10,"minimum":1,"default":1,"title":"Persons"}},{"name":"green_mode","in":"query","required":false,"schema":{"type":"string","default":"off","title":"Green Mode"}},{"name":"green_manual","in":"query","required":false,"schema":{"type":"number","minimum":0,"default":0,"title":"Green Manual"}},{"name":"lifetime_years","in":"query","required":false,"schema":{"type":"integer","maximum":40,"minimum":5,"default":30,"title":"Lifetime Years"}},{"name":"battery_life_years","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":40,"minimum":1},{"type":"null"}],"title":"Battery Life Years"}},{"name":"max_cycles","in":"query","required":false,"schema":{"anyOf":[{"type":"integer","maximum":15000,"minimum":2000},{"type":"null"}],"title":"Max Cycles"}},{"name":"house_type","in":"query","required":false,"schema":{"type":"string","default":"heated","title":"House Type"}},{"name":"battery_degradation","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":0.2,"minimum":0},{"type":"null"}],"title":"Battery Degradation"}},{"name":"solar_degradation","in":"query","required":false,"schema":{"anyOf":[{"type":"number","maximum":0.2,"minimum":0},{"type":"null"}],"title":"Solar Degradation"}},{"name":"inverter_replace","in":"query","required":false,"schema":{"type":"boolean","default":false,"title":"Inverter Replace"}},{"name":"inverter_replace_year","in":"query","required":false,"schema":{"type":"integer","maximum":40,"minimum":1,"default":15,"title":"Inverter Replace Year"}},{"name":"inverter_replace_cost","in":"query","required":false,"schema":{"type":"number","minimum":0,"default":20000,"title":"Inverter Replace Cost"}},{"name":"future_price_factor","in":"query","required":false,"schema":{"type":"number","maximum":3,"exclusiveMinimum":0,"default":1,"title":"Future Price Factor"}},{"name":"battery_only_economics","in":"query","required":false,"schema":{"type":"boolean","description":"Räkna IRR och payback på enbart batteriets värdeström. Använd när solcellerna redan är betalda och `capex_solar` därför är 0.","default":false,"title":"Battery Only Economics"},"description":"Räkna IRR och payback på enbart batteriets värdeström. Använd när solcellerna redan är betalda och `capex_solar` därför är 0."},{"name":"purchase_date","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"}},{"name":"paid","in":"query","required":false,"schema":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Paid"}},{"name":"purchase_date_solar","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date Solar"}},{"name":"purchase_date_battery","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date Battery"}},{"name":"paid_solar","in":"query","required":false,"schema":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"title":"Paid Solar"}},{"name":"paid_battery","in":"query","required":false,"schema":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"title":"Paid Battery"}},{"name":"profile_token","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Token"}},{"name":"pv_orient","in":"query","required":false,"schema":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Pv Orient"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Simulate Household Api V1 Simulate Household Get"}}}},"202":{"description":"Beräkningen är köad (kall cache). Svaret bär `warm.config_key` som pollas via `GET /warm/by-config`; gör sedan om anropet för att hämta resultatet."},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/simulate/flex-facit":{"get":{"tags":["betyg"],"summary":"Stödtjänst-facit per månad","description":"Vad hade ett batteri av given storlek gett i FCR-D per månad: fysiskt tak (brutto), förväntad nettoersättning via vald aggregator, och batteriets alternativvärde i spotoptimering för en typprofil. Ange `paid_sek` (hela fönstret, netto utbetalt) för ett omdöme mot spannet. Högst 12 månader, från 2020-01, t.o.m. innevarande månad (räknad t.o.m. i går). Månader före 2024-02 bär pay-as-bid-priser (`price_basis`) som ligger systematiskt över vad som betalades. Ingenting lagras.","operationId":"flex_facit_endpoint_api_v1_simulate_flex_facit_get","parameters":[{"name":"zone","in":"query","required":true,"schema":{"type":"string","description":"Elområde (styr spotpriset i alternativet; FCR-priset är nationellt).","title":"Zone"},"description":"Elområde (styr spotpriset i alternativet; FCR-priset är nationellt)."},{"name":"kw","in":"query","required":true,"schema":{"type":"number","maximum":10000,"exclusiveMinimum":0,"description":"Batteriets märkeffekt (kW).","title":"Kw"},"description":"Batteriets märkeffekt (kW)."},{"name":"kwh","in":"query","required":true,"schema":{"type":"number","maximum":10000,"exclusiveMinimum":0,"description":"Batteriets märkkapacitet (kWh).","title":"Kwh"},"description":"Batteriets märkkapacitet (kWh)."},{"name":"from","in":"query","required":true,"schema":{"type":"string","description":"Första månad, YYYY-MM.","title":"From"},"description":"Första månad, YYYY-MM."},{"name":"to","in":"query","required":true,"schema":{"type":"string","description":"Sista månad, YYYY-MM.","title":"To"},"description":"Sista månad, YYYY-MM."},{"name":"aggregator","in":"query","required":false,"schema":{"type":"string","description":"checkwatt | tibber | annan | flower (flower: inget estimat).","default":"checkwatt","title":"Aggregator"},"description":"checkwatt | tibber | annan | flower (flower: inget estimat)."},{"name":"paid_sek","in":"query","required":false,"schema":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"description":"Faktiskt utbetalt för hela fönstret, kr netto.","title":"Paid Sek"},"description":"Faktiskt utbetalt för hela fönstret, kr netto."},{"name":"pv_kwp","in":"query","required":false,"schema":{"type":"number","maximum":1000,"minimum":0,"description":"Typprofilens solceller (kWp), 0 = ingen sol.","default":10,"title":"Pv Kwp"},"description":"Typprofilens solceller (kWp), 0 = ingen sol."},{"name":"load_annual","in":"query","required":false,"schema":{"type":"number","maximum":1000000,"exclusiveMinimum":0,"description":"Typprofilens årsförbrukning (kWh).","default":20000,"title":"Load Annual"},"description":"Typprofilens årsförbrukning (kWh)."},{"name":"house_type","in":"query","required":false,"schema":{"type":"string","description":"heated | unheated.","default":"heated","title":"House Type"},"description":"heated | unheated."}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Flex Facit Endpoint Api V1 Simulate Flex Facit Get"}}}},"404":{"description":"Ingen data för den efterfrågade zonen eller marknaden."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/link":{"post":{"tags":["anläggning"],"summary":"Hämta eller skapa anläggningens läslänk","description":"Som `POST /profile/{token}/link`, med token i `Authorization: Bearer`.","operationId":"mint_link_bearer_api_v1_profile_link_post","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Mint Link Bearer Api V1 Profile Link Post"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."},"503":{"description":"Länkfunktionen är inte aktiverad på servern (krypteringsnyckel saknas)."}},"security":[{"ProfileToken":[]}]},"delete":{"tags":["anläggning"],"summary":"Ta bort anläggningens läslänk","description":"Som `DELETE /profile/{token}/link`, med token i `Authorization: Bearer`.","operationId":"revoke_link_bearer_api_v1_profile_link_delete","responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."}},"security":[{"ProfileToken":[]}]}},"/api/v1/profile/link/rotate":{"post":{"tags":["anläggning"],"summary":"Byt anläggningens läslänk","description":"Som `POST /profile/{token}/link/rotate`, med token i `Authorization: Bearer`.","operationId":"rotate_link_bearer_api_v1_profile_link_rotate_post","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Rotate Link Bearer Api V1 Profile Link Rotate Post"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."},"503":{"description":"Länkfunktionen är inte aktiverad på servern (krypteringsnyckel saknas)."}},"security":[{"ProfileToken":[]}]}},"/api/v1/profile/claim-code":{"post":{"tags":["anläggning"],"summary":"Skapa kopplingskod","description":"Som `POST /profile/{token}/claim-code`, med token i `Authorization: Bearer`.","operationId":"mint_claim_code_bearer_api_v1_profile_claim_code_post","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Mint Claim Code Bearer Api V1 Profile Claim Code Post"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."}},"security":[{"ProfileToken":[]}]}},"/api/v1/profile":{"get":{"tags":["anläggning"],"summary":"Anläggningens parametrar","description":"Anläggningens sparade parametrar: zon, batteri, sol, styrsystem, inköp (inklusive eventuell uppdelning mellan sol och batteri), egen tariff och reservgolv, plus optimeringsbetyget. Ingen timdata och inga personuppgifter utöver det som angetts. `data_since` är starten på anläggningens tidigaste lagrade intervall, timmar i karantän inräknade, `null` utan rader.","operationId":"get_profile_api_v1_profile_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Get Profile Api V1 Profile Get"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."}},"security":[{"ProfileToken":[]}]},"post":{"tags":["anläggning"],"summary":"Skapa anläggning","description":"Skapar en anläggning för löpande uppladdning och svarar **201** med `profile_token` (plus `account_linked`). Token är nyckeln till anläggningen och skickas som `Authorization: Bearer` på anropen nedan. Den visas bara här: Wolta lagrar den hashad.\n\nObligatoriskt: `zone` och batteri – antingen `battery_kwh`+`battery_kw` (båda > 0) eller `battery_declared: true` med paret utelämnat, om kapaciteten inte är känd än (Wolta mäter den ur driftdatan). Valfritt: `eff` (standard 0,9), `has_solar`, styrsystem (`control_system`, valideras strikt), inköpspris och inköpsdatum, egen tariff och reservgolv. Samma väg som Home Assistant-integrationen använder.","operationId":"create_profile_api_v1_profile_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileCreate"}}},"required":true},"responses":{"201":{"description":"Resursen skapades.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Create Profile Api V1 Profile Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["anläggning"],"summary":"Uppdatera anläggningen","description":"Uppdaterar en sparad anläggning utan ny uppladdning. Ekonomi, egen tariff (`null` återställer till landets schablon) och reservgolv är billiga ändringar; ändrad batteri- eller solstorlek räknar om betyget på den lagrade driftdatan. `battery_kwh`/`battery_kw` kan aldrig sättas till `null` eller ≤ 0 (422) – batteriet kan inte tas bort eller nollas via PATCH.\n\nElområdet får rättas om det blev fel vid skapandet, men bara inom samma valuta - de sparade beloppen är angivna i zonens valuta och räknas inte om. Ett byte som korsar valutagränsen ger 422; radera och skapa om anläggningen i stället. Rättelsen räknar om betyg och ekonomi mot den nya prisserien, så talen ändras. Samma värde som redan är lagrat är ett no-op.\n\n`solar_events` beskriver solceller köpta i etapper: `[{date, kwp, cost_sek}]`, där varje etapp anger anläggningens TOTALA kWp efter just den etappen, inte etappens egen tillökning. `battery_events` kan också bära valfria `power_kw` och `eff` per etapp med samma totalt-efter-etappen-semantik; en etapp som utelämnar dem ärver närmast föregående etapps värde.\n\nSå länge en tidslinje finns är den sanningskällan för sina härledda fält. `paid_solar_sek` och `purchase_date_solar` kan aldrig sättas direkt medan `solar_events` finns (422) – redigera etapperna i stället. En `pv_kwp`-PATCH flyttar i stället in värdet i soltidslinjens senaste etapp; `battery_kw`/`eff` gör detsamma, men bara om batteritidslinjen redan bär fältet (annars gäller fortfarande den skalära kolumnen). Att nolla ett sådant fält till `null` när tidslinjen bär det ger 422 i stället för att tyst motsäga etapperna. `purchase_date` får sättas till ett datum på eller före den tidigaste etappen – den giltiga situationen att en komponent saknar eget datum – men både ett senare datum och en explicit `null` (rensning) ger 422 medan en tidslinje finns, eftersom båda motsäger etapperna.","operationId":"patch_profile_api_v1_profile_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilePatch"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Patch Profile Api V1 Profile Patch"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ProfileToken":[]}]}},"/api/v1/profile/adopt":{"post":{"tags":["anläggning"],"summary":"Gör anläggningen till integration","description":"Konverterar en anläggning som skapats via webben till en integrationsanläggning, så att den kan ta emot löpande data. Home Assistant-integrationen anropar den när den kopplas till en befintlig anläggning. Idempotent: redan konverterad ger `{\"adopted\": false}`. Anläggningar utan batteri ger 422.","operationId":"adopt_profile_api_v1_profile_adopt_post","requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AdoptRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Adopt Profile Api V1 Profile Adopt Post"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ProfileToken":[]}]}},"/api/v1/profile/data":{"put":{"tags":["anläggning"],"summary":"Fyll på driftdata","description":"Lägger till driftdata löpande: `{rows: [...]}`. Varje rad kräver `ts` **med tidszon** (naiv tidsstämpel ger 422 för hela batchen), `batt_charged_kwh` och `batt_discharged_kwh`. `solar_kwh`, `grid_import_kwh` och `grid_export_kwh` är valfria men **defaultar till 0**: utelämnas nätflödena lagras nollor utan fel, och betyget räknas på ett hus som aldrig importerar el.\n\nAlla energivärden måste ligga mellan 0 och 500 per rad. Varje klocktimme rimlighetsprövas dessutom mot redan lagrat tillstånd: överstiger något fält en fysisk eller statistisk gräns, till exempel en mätarställning i stället för en timmes energi, läggs hela timmen i karantän och räknas inte, i stället för att batchen nekas. `quarantined_hours` och `quarantined_rows` i svaret räknar dem, och `repaired_battery_rows` räknar de karantänerade raderna som bar batteriflöde. En korrigerad omsändning lyfter tillbaka timmen.\n\nUpsert sker på exakt tidsstämpel, så att skicka om samma rader är riskfritt. Byter ni upplösning (timme till kvart) eller flyttar tidsstämplarna ligger de gamla raderna kvar och dygnet dubbelräknas: radera anläggningen och börja om i stället. Högst 40 000 rader per anrop (fler ger **422**) och 80 000 rader per anläggning totalt (**413**).\n\n`battery_state` och `battery_sources` är valfria: de samlas in för senare kapacitetsmätning och påverkar inte betyget. Ett ogiltigt värde i dem ger 422 för hela anropet, flödena inräknade.\n\n`data_since` i svaret är starten på anläggningens tidigaste lagrade intervall efter anropet, timmar i karantän inräknade, `null` utan rader. En klient kan jämföra den med sin egen historik och skicka det som saknas före den; en karantänerad timme är mottagen och ska inte skickas igen.","operationId":"put_data_api_v1_profile_data_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataPut"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Put Data Api V1 Profile Data Put"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."},"413":{"description":"Anläggningens totala lagringstak (80 000 rader) är nått. Radera anläggningen och skapa en ny."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"ProfileToken":[]}]}},"/api/v1/profile/recompute":{"post":{"tags":["anläggning"],"summary":"Begär omräkning","description":"Begär omräkning av betyg och ekonomi efter ny data. Svarar **202**; en bakgrundsberäkning tar vid och följs via `GET /warm`. Cooldown 24 timmar (429 med `Retry-After` om den redan körts). En parameterändring via PATCH nollställer cooldownen.","operationId":"recompute_api_v1_profile_recompute_post","responses":{"202":{"description":"Begäran är mottagen och köad. Resultatet hämtas genom att polla.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Recompute Api V1 Profile Recompute Post"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."},"429":{"description":"Omräkningen har redan körts inom cooldownen. `Retry-After` anger när nästa är tillåten."}},"security":[{"ProfileToken":[]}]}},"/api/v1/profile/results":{"get":{"tags":["anläggning"],"summary":"Senaste resultatet","description":"Senaste färdiga beräkning: optimeringsbetyg med komponentuppdelning och tillämpad tariff, ekonomi och jobbstatus. Läser bara det som redan är beräknat.\n\nAtt `decision`/`history` är null betyder inte alltid att beräkningen pågår: ekonomin finns bara för svenska elområden (övriga zoner får betyg men aldrig ekonomi) och kräver minst 30 dygns data. Polla alltså inte i väntan på ekonomi utanför Sverige eller på ett kortare fönster, `status` kan vara `done` ändå.\n\n`history.realized` ger den realiserade avkastningen på en daterad kassaflödesserie: `capex_events` bokför capex som negativa poster på varje etapps eget datum, följt av de faktiska årsbesparingarna och en framskrivning till `horizon_end` – en fast 30-årshorisont från det första köpet. `irr_status` är `ok`, `ambiguous` (serien har fler än en matematiskt giltig ränta – ingen enskild siffra är ärlig), `insufficient` (mindre än ett års data, för kort för att uttala en årsränta) eller `none` (ingen ränta finns). Break-even är seriens SISTA nollgenomgång, inte den första: ett senare köp kan göra en redan återbetald anläggning obetald igen.","operationId":"results_api_v1_profile_results_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Results Api V1 Profile Results Get"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."}},"security":[{"ProfileToken":[]}]}},"/api/v1/calibration":{"delete":{"tags":["anläggning"],"summary":"Radera anläggningen","description":"Raderar anläggningen och all dess data: profil, timdata, betyg och cache. Kan inte ångras. Token skickas i `Authorization: Bearer`.","operationId":"delete_submission_api_v1_calibration_delete","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Delete Submission Api V1 Calibration Delete"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."}},"security":[{"ProfileToken":[]}]}},"/api/v1/calibration/ping":{"get":{"tags":["drift"],"summary":"Enkel svarskontroll","description":"Svarar `{\"ok\": true}`. Används för att kontrollera att API:t nås över nätet.","operationId":"ping_api_v1_calibration_ping_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Ping Api V1 Calibration Ping Get"}}}}}}},"/api/v1/calibration/export-script":{"get":{"tags":["betyg"],"summary":"Exportskript för Home Assistant","description":"Laddar ner `export_energy_csv.py`, hjälpskriptet som plockar ut driftdata ur Home Assistant i det format uppladdningsvägarna väntar sig.","operationId":"export_script_api_v1_calibration_export_script_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{}}}}}}},"/api/v1/calibration/compute":{"post":{"tags":["betyg"],"summary":"Prisstyrd-faktor ur egen driftdata","description":"Laddar upp egen driftdata (CSV) och räknar fram en personlig prisstyrd-faktor, alltså hur väl förbrukningen följer priset. `store=true` sparar profilen och returnerar en profil-token. Zonen måste vara SE1–SE4.","operationId":"compute_api_v1_calibration_compute_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_compute_api_v1_calibration_compute_post"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Compute Api V1 Calibration Compute Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/calibration/summary":{"get":{"tags":["betyg"],"summary":"Jämförelsedata för betyget","description":"Aggregatet som enskilda betyg ställs mot: prisstyrd-faktor (median, p25/p75) och ett betygsblock (median och max) över anläggningarna i jämförelsedatan, med uppdelning per zon och styrsystem.\n\n`total_plants` är antalet anläggningar med accepterad data. Övriga `n`-fält är **effektiv** stickprovsstorlek (Kish) på den viktade mängden, inte ett radantal: en flotta från en och samma partner viktas ned som helhet, så `n` kan vara lägre än antalet anläggningar bakom siffran. Segment vars effektiva `n` understiger 5 utelämnas.","operationId":"summary_api_v1_calibration_summary_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Summary Api V1 Calibration Summary Get"}}}}}}},"/api/v1/calibration/{token}":{"delete":{"tags":["anläggning"],"summary":"Radera anläggningen (token i sökväg)","description":"Samma radering som `DELETE /calibration`, med token i sökvägen. 404 om token är okänd.","operationId":"delete_submission_api_v1_calibration__token__delete","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Delete Submission Api V1 Calibration  Token  Delete"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}":{"get":{"tags":["anläggning"],"summary":"Anläggningens parametrar (token i sökväg)","description":"Samma svar som `GET /profile`, med token i sökvägen i stället för i `Authorization`-headern. Nya klienter bör använda headervarianten: en token i en URL hamnar i loggar och webbläsarhistorik.","operationId":"get_profile_api_v1_profile__token__get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Profile Api V1 Profile  Token  Get"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["anläggning"],"summary":"Uppdatera anläggningen (token i sökväg)","description":"Samma semantik som `PATCH /profile`, med token i sökvägen. Nya klienter bör använda headervarianten.","operationId":"patch_profile_api_v1_profile__token__patch","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilePatch"}}}},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Patch Profile Api V1 Profile  Token  Patch"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}/link":{"post":{"tags":["anläggning"],"summary":"Hämta eller skapa anläggningens läslänk","description":"Returnerar anläggningens läslänk-token (`wpl_…`) och skapar den om den inte finns. **Idempotent**: upprepade anrop ger samma token och har inga sidoeffekter. Länken ger läsning av hela anläggningsvyn men skriver ingenting – aldrig ekonomi, radering, nytt token, delning eller tekniska fält. Byt token med `/link/rotate`.","operationId":"mint_link_api_v1_profile__token__link_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Mint Link Api V1 Profile  Token  Link Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"503":{"description":"Länkfunktionen är inte aktiverad på servern (krypteringsnyckel saknas)."}}},"delete":{"tags":["anläggning"],"summary":"Ta bort anläggningens läslänk","description":"Återkallar läslänken. Idempotent: svarar 204 även när ingen länk finns. Fungerar även när länkfunktionen i övrigt är avstängd – att kunna återkalla en läckt länk får aldrig bero på serverns krypteringsnyckel.","operationId":"revoke_link_api_v1_profile__token__link_delete","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"204":{"description":"Lyckat svar, tom kropp."},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}/link/rotate":{"post":{"tags":["anläggning"],"summary":"Byt anläggningens läslänk","description":"Skapar en ny läslänk. Den gamla slutar fungera omedelbart. Rotation sker aldrig som bieffekt av något annat anrop.","operationId":"rotate_link_api_v1_profile__token__link_rotate_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Rotate Link Api V1 Profile  Token  Link Rotate Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"503":{"description":"Länkfunktionen är inte aktiverad på servern (krypteringsnyckel saknas)."}}}},"/api/v1/profile/{token}/claim-code":{"post":{"tags":["anläggning"],"summary":"Skapa kopplingskod","description":"Skapar en engångskod som kopplar anläggningen till ett wolta.se-konto. Koden gäller i 10 minuter och kan bara användas en gång; en ny kod ersätter en tidigare oanvänd. Lös in den under Konto → Koppla anläggning när du är inloggad.","operationId":"mint_claim_code_api_v1_profile__token__claim_code_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Mint Claim Code Api V1 Profile  Token  Claim Code Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}/adopt":{"post":{"tags":["anläggning"],"summary":"Gör anläggningen till integration (token i sökväg)","description":"Samma semantik som `POST /profile/adopt`, med token i sökvägen. Ett valfritt `client_plant_id` i kroppen stämplar anläggningens stabila identitet, så att den känns igen om integrationen installeras om.","operationId":"adopt_profile_api_v1_profile__token__adopt_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"requestBody":{"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/AdoptRequest"},{"type":"null"}],"title":"Body"}}}},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Adopt Profile Api V1 Profile  Token  Adopt Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}/data":{"put":{"tags":["anläggning"],"summary":"Fyll på driftdata (token i sökväg)","description":"Samma semantik och gränser som `PUT /profile/data`, med token i sökvägen. `battery_state` och `battery_sources` är valfria: de samlas in för senare kapacitetsmätning och påverkar inte betyget. Ett ogiltigt värde i dem ger 422 för hela anropet, flödena inräknade. Nya klienter bör använda headervarianten. `data_since` i svaret är starten på anläggningens tidigaste lagrade intervall efter anropet, timmar i karantän inräknade, `null` utan rader.","operationId":"put_data_api_v1_profile__token__data_put","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataPut"}}}},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Put Data Api V1 Profile  Token  Data Put"}}}},"404":{"description":"Okänd token."},"413":{"description":"Anläggningens totala lagringstak (80 000 rader) är nått. Radera anläggningen och skapa en ny."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}/recompute":{"post":{"tags":["anläggning"],"summary":"Begär omräkning (token i sökväg)","description":"Samma semantik som `POST /profile/recompute`, med token i sökvägen.","operationId":"recompute_api_v1_profile__token__recompute_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"202":{"description":"Begäran är mottagen och köad. Resultatet hämtas genom att polla.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Recompute Api V1 Profile  Token  Recompute Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Omräkningen har redan körts inom cooldownen. `Retry-After` anger när nästa är tillåten."}}}},"/api/v1/profile/{token}/results":{"get":{"tags":["anläggning"],"summary":"Senaste resultatet (token i sökväg)","description":"Samma svar som `GET /profile/results`, med token i sökvägen. Kör aldrig en beräkning i anropsvägen, allt läses ur cache.","operationId":"results_api_v1_profile__token__results_get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Results Api V1 Profile  Token  Results Get"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/grade/check-plant":{"post":{"tags":["betyg"],"summary":"Finns anläggningen redan?","description":"Billig kontroll av om anläggningen redan är sparad, matchad på ett saltat fingeravtryck av sensornamn och zon. Svarar `{match, can_update}` och räknar inget betyg.\n\n`can_update` säger om **anroparen** får ersätta den matchade raden, alltså om hen bevisar innehav (radens egen profil-token eller en inloggad session som äger den). En matchning i sig ger ingen skrivrätt, och en anläggning som strömmar via en integration ersätts aldrig den här vägen. POST just för att beviset aldrig ska hamna i en sökväg.","operationId":"check_plant_api_v1_grade_check_plant_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckPlantIn"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Check Plant Api V1 Grade Check Plant Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/grade":{"post":{"tags":["betyg"],"summary":"Ladda upp driftdata för betyg","description":"Startar en betygsberäkning. Validerar synkront (zon, batteri och CSV ger 422 direkt), lagrar datan och köar beräkningen: svaret är **202** med `profile_token` och `status: pending`. Betyget hämtas sedan genom att polla `GET /warm` med token i `Authorization: Bearer`.\n\nKräver minst 7 dygns data. 7–29 dygn ger ett preliminärt betyg (`preliminary: true`) som kan svänga och som varken ingår i jämförelsedatan eller öppnar ekonomin; fullt betyg kräver 30 dygn.\n\nEtt anonymt betyg (siffra och elområde) sparas alltid för jämförelsen. `share_profile` är opt-in och styr om den råa timdatan behålls. Skickas `profile_token` i stället för fil räknas betyget om på redan lagrad data.\n\n`battery_declared=true` utan `nameplate_kwh`/`nameplate_kw` betyder att batteriet finns men att kapaciteten ska mätas ur driftdatan. Mätningen kräver att serien sparas, så kombinationen med `share_profile=false` ger **422**: ange märkdata, ett känt `battery_kwh`/`battery_kw`-par eller spara profilen.","operationId":"grade_api_v1_grade_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_grade_api_v1_grade_post"}}},"required":true},"responses":{"202":{"description":"Uppladdningen är godkänd och beräkningen köad. Svaret bär `profile_token` och `status: pending`; polla `GET /warm`.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Grade Api V1 Grade Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/sizing":{"post":{"tags":["anläggning"],"summary":"Optimal batteristorlek","description":"Sveper batteristorlekar mot en driftprofil och redovisar per storlek årsvärde, cykellivslängd och ekonomi (NPV, IRR och payback), både för ett nytt batteri från noll och som marginell utökning från nuvarande storlek. Värdet skalas med den uppmätta skickligheten i den faktiska styrningen, inte med ett teoretiskt optimum.\n\nTar samma CSV-format som `POST /grade`, eller `profile_token` för en redan sparad anläggning. Kall väg svarar 202 med `warm.config_key`: polla `GET /warm/by-config` och gör om anropet när beräkningen är klar.","operationId":"sizing_endpoint_api_v1_sizing_post","requestBody":{"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_sizing_endpoint_api_v1_sizing_post"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Sizing Endpoint Api V1 Sizing Post"}}}},"202":{"description":"Beräkningen är köad (kall cache). Svaret bär `warm.config_key` som pollas via `GET /warm/by-config`; gör sedan om anropet för att hämta resultatet."},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/warm/by-config/{config_key}":{"get":{"tags":["betyg"],"summary":"Status för fristående beräkning","description":"Status för en köad beräkning utan anläggning (hushållssimulering eller dimensionering). `config_key` kommer ur 202-svaret från den beräkning som köades. Pollas tills `done`, varefter ursprungsanropet görs om och då svarar 200 med resultatet. 404 om nyckeln är okänd.","operationId":"warm_by_config_api_v1_warm_by_config__config_key__get","parameters":[{"name":"config_key","in":"path","required":true,"schema":{"type":"string","title":"Config Key"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Warm By Config Api V1 Warm By Config  Config Key  Get"}}}},"404":{"description":"Okänt jobb."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/warm":{"get":{"tags":["betyg"],"summary":"Status för köad beräkning","description":"Pollas efter `POST /grade` tills beräkningen är klar: `status` är `pending`, `running`, `done` eller `error`, med `step` och `steps_done`/`steps_total` för progress. När första steget är klart ingår betyget i svaret.\n\nAnläggningens profil-token skickas i `Authorization: Bearer`.","operationId":"warm_status_bearer_api_v1_warm_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Warm Status Bearer Api V1 Warm Get"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."}},"security":[{"ProfileToken":[]}]}},"/api/v1/warm/{token}":{"get":{"tags":["betyg"],"summary":"Status för köad beräkning (token i sökväg)","description":"Föråldrad variant av `GET /warm` med token i sökvägen. En token i en URL hamnar i loggar, webbläsarhistorik och `Referer` (CWE-598), så nya klienter ska skicka den i `Authorization: Bearer`. Endpointen finns kvar tills redan utlevererade webbklienter åldrats ut och tas sedan bort.","operationId":"warm_status_api_v1_warm__token__get","deprecated":true,"parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Warm Status Api V1 Warm  Token  Get"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/analysis":{"get":{"tags":["betyg"],"summary":"Analys av styrningen","description":"Var batteriets styrning tappar värde: ånger per dygn mot bästa möjliga handling, summerad per sorts avvikelse och per timme, samt ett fingeravtryck av hur batteriet faktiskt kördes (`fingerprint`: summor per månad och lokal timme). Timmen är intervallets lokala klocktimme, 0–23: på dygnet då sommartiden börjar saknas timme 2, och på dygnet då den slutar bär timme 2 två timmars intervall. Fingeravtryckets `a_ch_an` och `a_dis_an` är uppmätt laddning och urladdning över samma intervall som den optimala handlingen (`o_ch`, `o_dis`, antal `o_intervals`), så att de två går att jämföra över samma dygn.\n\n`tz` är anläggningens tidszon (IANA-namn), den som dygnen och timmarna räknas i. `wear_ore_per_kwh` är slitaget per kWh laddat eller urladdat som kronorna räknades med. Varje dygnsrad bär `computed_at`, när raden senast räknades. `summary.day_bucket` är ånger per dygn och sorts avvikelse, med samma urval som `summary.buckets` (summan över dygnen är hinkens), en rad per dygn och hink som har intervall.\n\n`status` är `no_data`, `pending`, `running`, `done` eller `error`. `pending` och `running` betyder att en körning väntar eller pågår; dygn som redan räknats ingår då i svaret, och `progress` säger hur långt körningen kommit (talen går inte alltid framåt: en körning som läggs tillbaka i kön kan börja om). `done` betyder att det finns dygn och ingen körning väntar eller pågår. `done` tillsammans med `job.status` = `error` betyder att senaste uppdateringen inte slutfördes, så de lagrade dygnen kan vara inaktuella. `error` betyder att körningen felade och att inga dygn finns. `no_data` betyder att ingen analys har körts. `summary` är `null` och `fingerprint` en tom lista när dygn saknas.\n\nAnalysen räknas bara när Wolta behåller timserien och betyget är uppmätt och godkänt. Annars är `status` `no_data` och `unavailable_reason` säger varför: `series_not_kept` (uppladdning utan sparad timserie), `grade_not_measured` (betyget är en uppskattning, inte uppmätt) eller `grade_rejected` (betyget underkändes, t.ex. för att laddning och urladdning ser omkastade ut). `unavailable_reason` är `null` när analysen får räknas och när inget betyg är räknat än. Ett preliminärt betyg, och ett betyg som hålls utanför jämförelsen för extern styrning, ger analys som vanligt.\n\nVarje dygn värderas med skatte- och kreditreglerna för sitt eget kalenderår (`rule_year` på dygnet). `regime_year` är året betyget räknas med. `year_terms` redovisar villkoren per kalenderår bland dygnen: `rule_year` (regelåret; `rules_fallback` är `true` när året saknas i skattetabellen och `regime_year`:s regler används), `credit_ore` (skattereduktionen för mikroproduktion det året, öre per kWh) och `credit_margin`. Reduktionens underlag är det lägsta av inmatat, uttaget och 30 000 kWh under kalenderåret, och `credit_margin` säger vilken term som binder: `export` (inmatat under året är lägst, så en exporterad kWh ger reduktionen), `import` (uttaget är lägst, så en importerad kWh ger den), `none` (taket på 30 000 kWh, eller inmatat lika med uttaget) eller `null` (ingen reduktion det året). Gränsen avgörs på `export_kwh` och `import_kwh`, summorna i den lagrade serien för året; `observed_days` av `days_in_year` säger hur stor del av året de täcker, och ett ofullständigt år är en skattning. Varje dygn bär sin egen `credit_margin`.\n\n`worst_days` listar de högst 3 analyserade dygnen med störst ånger, störst först (lika ånger: det senare dygnet först).\n\n`view=status` ger en lätt läsning för att följa en körning medan `status` är `pending` eller `running`: bara `status`, `unavailable_reason`, `job`, `progress`, `analysis_version`, `days_stored` (antal lagrade dygn som den fulla läsningen visar) och `last_computed_at` (senaste `computed_at` bland dem, `null` utan dygn). `status` och `progress` är desamma som i den fulla läsningen. Utan parametern, eller med `view=full`, kommer hela svaret; andra värden ger 422.\n\nAnalysen köas efter varje betygsberäkning. Ett dygn som inte går att analysera finns kvar i `days`, med skälet i `undefined_reason`: `reservation`, `no_lookahead`, `parameter_change`, `export_over_import`, `okand_startniva`, `external_infeasible` eller `berakningsfel`. Gäller flera skäl redovisas dygnet under det första i den ordningen. Seriens sista dygn, och dygnet före ett uppehåll i serien, saknar ett följande dygn att jämföra mot och kan därför inte analyseras (`no_lookahead`); analysen når alltså som mest till dygnet före seriens sista, och ligger i det avseendet ett dygn efter betyget. `okand_startniva`: batteriets nivå vid dygnets början är inte känd – dygnet ligger i början av analysperioden eller efter ett uppehåll i serien, och batteriet har ännu inte varit tomt eller fullt. Nivån blir känd när det har varit det, och dygnet efter är det första som analyseras. Historik före perioden används när den finns. På ett sådant dygn är den uppmätta nivån (`open_soc`, `close_soc`, `a_soc_min`, `a_soc_max` och intervallens `a_soc`) en undre gräns, och ett intervall räknas bara som utanför batterimodellen när det är det från varje möjlig nivå.\n\nAnläggningens profil-token skickas i `Authorization: Bearer`.","operationId":"analysis_bearer_api_v1_analysis_get","security":[{"ProfileToken":[]}],"parameters":[{"name":"view","in":"query","required":false,"schema":{"enum":["full","status"],"type":"string","description":"`full` (standard) ger hela svaret, `status` bara status och förlopp för pollning.","default":"full","title":"View"},"description":"`full` (standard) ger hela svaret, `status` bara status och förlopp för pollning."}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Analysis Bearer Api V1 Analysis Get"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."},"422":{"description":"`view` är varken `full` eller `status`."}}}},"/api/v1/analysis/intervals":{"get":{"tags":["betyg"],"summary":"Analysens intervall","description":"Intervallraderna för dygnen `from`–`to` (båda inräknade, högst 31 dygn per anrop), kolumnvis: `columns` har en lista per fält med ett värde per intervall i tidsordning – flöden, priser, uppmätt och optimal handling, ånger och klassning. För dygn som inte analyserats är optimal handling, ånger och klassning `null`; flöden, priser och uppmätt nivå finns ändå.\n\nAnläggningens profil-token skickas i `Authorization: Bearer`.","operationId":"analysis_intervals_bearer_api_v1_analysis_intervals_get","security":[{"ProfileToken":[]}],"parameters":[{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date","title":"From"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date","title":"To"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Analysis Intervals Bearer Api V1 Analysis Intervals Get"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."},"422":{"description":"Spannet är ogiltigt: `from` ligger efter `to`, spannet överstiger 31 dygn, eller ett datum saknas eller är inte ett giltigt datum."}}}},"/api/v1/quarantine":{"get":{"tags":["anläggning"],"summary":"Timmar som inte räknas","description":"Klocktimmar som inte räknas för att ett mätvärde inte är fysiskt möjligt, till exempel en hel mätarställning i stället för en timmes energi. Timmarna är undantagna från betyg, årsuppräkning, ekonomi och analys. Nyast först.\n\nPer timme anges de fält som bröt, värdet och taket i kWh för klocktimmen och vilket lager i regeln som fällde timmen: `A` över 200 kWh på en timme, `B` solproduktion när solen stod under horisonten i hela landet, `C` över batteriets effekt × 1,5 eller solcellernas toppeffekt × 1,3, `D` över fyra gånger anläggningens egen 99:e percentil (med ett golv per fält). `evidence` finns bara på lager C: `soc_refuted` (laddningsnivån motsäger värdet), `unsupported` (timmens övriga mätningar bär inte värdet) eller `none` (värdet går inte att bekräfta).\n\n`systematic` är sant när orimliga timmar är så många att felet ser systematiskt ut (fel enhet eller felkopplad sensor). Då läggs ingenting i karantän: timmarna räknas med, men anläggningen jämförs inte med andra. Listan är då tom.\n\nSkickas en timme igen med rättade värden bedöms den på nytt.","operationId":"quarantine_bearer_api_v1_quarantine_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuarantineOut"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Okänd token."}},"security":[{"ProfileToken":[]}]}},"/api/v1/share":{"post":{"tags":["delning"],"summary":"Skapa delningslänk","description":"Skapar en delbar, publik länk till en anläggnings betyg utifrån dess profil-token. `wear_on` styr om slitage räknas in i den delade vyn. Svarar 201 med länkens id. Okänd token ger 404.","operationId":"share_create_api_v1_share_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareCreate"}}},"required":true},"responses":{"201":{"description":"Resursen skapades.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Share Create Api V1 Share Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/interest":{"post":{"tags":["integrationer"],"summary":"Anmäl intresse för ett styrsystem","description":"Registrerar att någon vill se stöd för ett styrsystem Wolta ännu inte kopplar mot. E-postadress är valfri och används bara för ett engångsmejl när stödet finns. Samma adress och system två gånger räknas en gång. Okänt system ger 422. Med `system` = `annat` kan systemets namn anges i `system_name`.","operationId":"register_interest_api_v1_interest_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InterestIn"}}},"required":true},"responses":{"201":{"description":"Resursen skapades.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Register Interest Api V1 Interest Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/reduxi/onboard":{"post":{"tags":["integrationer"],"summary":"Anslut Reduxi-styrsystem","description":"Provisionerar ett konto på Woltas MQTT-brygga för ett Reduxi-styrsystem och skapar anläggningen. Svaret bär brokeradress, färska inloggningsuppgifter och anläggningens `profile_token`. Uppgifterna visas bara här.","operationId":"onboard_api_v1_reduxi_onboard_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/elpris_api__api__reduxi_onboard__OnboardRequest"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Onboard Api V1 Reduxi Onboard Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/reduxi/{token}/status":{"get":{"tags":["integrationer"],"summary":"Reduxi-kopplingens status","description":"Visar om bryggan tar emot data för anläggningen och när senast.","operationId":"status_api_v1_reduxi__token__status_get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Status Api V1 Reduxi  Token  Status Get"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/reduxi/{token}/rotate":{"post":{"tags":["integrationer"],"summary":"Rotera Reduxi-lösenord","description":"Provisionerar om samma enhet med ett nytt brokerlösenord. Det gamla slutar fungera, så styrsystemets inställningar måste uppdateras.","operationId":"rotate_api_v1_reduxi__token__rotate_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Rotate Api V1 Reduxi  Token  Rotate Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/reduxi/{token}":{"delete":{"tags":["integrationer"],"summary":"Koppla från Reduxi","description":"Tar bort brokerkontot och raderar anläggningen med profil, koppling och cache.","operationId":"offboard_api_v1_reduxi__token__delete","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Offboard Api V1 Reduxi  Token  Delete"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/sonnen/onboard":{"post":{"tags":["integrationer"],"summary":"Anslut sonnenBatterie","description":"Självbetjäning för sonnenBatterie-ägare: skapar en anläggning och en webhook-adress som batteriet postar sin driftdata till. Ingest-token visas **en gång** och lagras hashat, så den måste sparas direkt.","operationId":"onboard_api_v1_sonnen_onboard_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/elpris_api__api__sonnen__OnboardRequest"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Onboard Api V1 Sonnen Onboard Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/ingest/sonnen/{ingest_token}":{"post":{"tags":["integrationer"],"summary":"Webhook-mottagare för Sonnen","description":"Tar emot batteriets egna webhook-anrop. Anropas av batteriet, inte av en integration: adressen kommer ur anslutningsflödet ovan.\n\nTidsstämpeln sätts vid mottagandet, eftersom batteriets egen tidsstämpel är lokal tid utan tidszon och därför inte går att lita på. Batteriet läser inte svaret; statuskoderna finns för felsökning.","operationId":"receive_webhook_api_v1_ingest_sonnen__ingest_token__post","parameters":[{"name":"ingest_token","in":"path","required":true,"schema":{"type":"string","title":"Ingest Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Receive Webhook Api V1 Ingest Sonnen  Ingest Token  Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}/sonnen":{"get":{"tags":["integrationer"],"summary":"Sonnen-kopplingens status (token i sökväg)","description":"Samma status som kontovägen, för den som håller anläggningens profil-token.","operationId":"sonnen_status_token_api_v1_profile__token__sonnen_get","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sonnen Status Token Api V1 Profile  Token  Sonnen Get"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["integrationer"],"summary":"Koppla från sonnenBatterie (token i sökväg)","description":"Kopplar bort batteriet från anläggningen bakom profil-token.","operationId":"sonnen_detach_token_api_v1_profile__token__sonnen_delete","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sonnen Detach Token Api V1 Profile  Token  Sonnen Delete"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}/sonnen/attach":{"post":{"tags":["integrationer"],"summary":"Koppla sonnenBatterie (token i sökväg)","description":"Skapar webhook-adressen för anläggningen bakom profil-token. Ingest-token visas en gång.","operationId":"sonnen_attach_token_api_v1_profile__token__sonnen_attach_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sonnen Attach Token Api V1 Profile  Token  Sonnen Attach Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/profile/{token}/sonnen/rotate":{"post":{"tags":["integrationer"],"summary":"Rotera Sonnen-token (token i sökväg)","description":"Mintar en ny ingest-token. Den gamla slutar fungera omedelbart.","operationId":"sonnen_rotate_token_api_v1_profile__token__sonnen_rotate_post","parameters":[{"name":"token","in":"path","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sonnen Rotate Token Api V1 Profile  Token  Sonnen Rotate Post"}}}},"404":{"description":"Okänd token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/partner/me":{"get":{"tags":["partner"],"summary":"Partnerns status och gränser","description":"Partnerskapets aktuella status: namn, tier, antal anläggningar samt de gränser som gäller just er (`plant_limit` och `rate_max_per_min`).\n\nLäs gränserna härifrån i stället för att hårdkoda dem: de ändras när partnerskapet uppgraderas. Bra första anrop för att verifiera att nyckeln fungerar.","operationId":"me_api_v1_partner_me_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PartnerMeOut"}}}},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Partnern är avstängd. Kontakta partner@wolta.se.","content":{"application/json":{"example":{"detail":"partnern är avstängd"}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}},"security":[{"PartnerKey":[]}]}},"/api/v1/partner/plants":{"post":{"tags":["partner"],"summary":"Skapa anläggning","description":"Skapar en anläggning som motsvarar en av era batterianläggningar. Svarar **201** med `link_token`, slutkundslänkens nyckel, som bara visas i det här svaret.\n\nAnropet är idempotent på ert `client_plant_id`: samma id igen ger **200** med `link_token: null` och lämnar den befintliga raden orörd, även om kroppen skiljer sig. Använd `PATCH` för att ändra en anläggning som redan finns. Idempotenskontrollen körs före tier-gränsen, så ett upprepat anrop går igenom även när kvoten är full.\n\n`client_plant_id` används som sökvägssegment i övriga anrop och måste därför vara URL-säkert: mellanslag, `/`, `?`, `#`, `%` och backslash ger 422, liksom ett id som bara är `.` eller `..`. Övriga tecken går bra, högst 128.","operationId":"create_plant_api_v1_partner_plants_post","security":[{"PartnerKey":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlantCreate"}}}},"responses":{"200":{"description":"Anläggningen fanns redan (idempotent upprepning). `link_token` är null.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlantCreated"}}}},"201":{"description":"Anläggningen skapades. `link_token` visas bara här.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlantCreated"}}}},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Partnern är avstängd. Kontakta partner@wolta.se.","content":{"application/json":{"example":{"detail":"partnern är avstängd"}}}},"409":{"description":"Tier-gränsen för antal anläggningar är nådd. Radera en oanvänd anläggning eller begär en uppgradering.","content":{"application/json":{"example":{"detail":{"error":"plant_limit_reached","plant_limit":10}}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}}},"get":{"tags":["partner"],"summary":"Lista flottan","description":"Er flotta med datatäckning och betygsstatus per anläggning: `first_hour`, `last_hour` och `n_days` (antal distinkta lokala dygn med data, räknat tidszonsmedvetet). Använd dem för att upptäcka luckor i er datamatning.\n\n`total` är hela flottan, inte antalet rader på sidan. `limit` måste vara större än 0 och klipps tyst till 500.","operationId":"list_plants_api_v1_partner_plants_get","security":[{"PartnerKey":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlantsPage"}}}},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Partnern är avstängd. Kontakta partner@wolta.se.","content":{"application/json":{"example":{"detail":"partnern är avstängd"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}}}},"/api/v1/partner/plants/{client_plant_id}":{"patch":{"tags":["partner"],"summary":"Uppdatera anläggning","description":"Uppdaterar de tekniska fälten på en anläggning. Bara de fält som skickas ändras.\n\nPartnern äger `control_system`, `battery_kwh`, `battery_kw`, `eff`, `nameplate_kwh` och `reserve_pct`. Slutkundens fält (ekonomi, elavtal, betygsfönster) kan inte sättas härifrån: ett sådant fält i kroppen ger **403** och inget skrivs.\n\nSkicka aldrig `null` för att nollställa, det ger **422**; utelämna fältet i stället. `zone` accepteras i kroppen men bara med samma värde som redan är lagrat (no-op) eftersom zonen styr valuta, skatt, tariff och tidszon för hela betygsberäkningen. Ett ändrat värde ger 422.\n\nSvaret innehåller `client_plant_id` plus de partnerägda fälten efter uppdateringen, aldrig slutkundens värden.","operationId":"patch_plant_api_v1_partner_plants__client_plant_id__patch","security":[{"PartnerKey":[]}],"parameters":[{"name":"client_plant_id","in":"path","required":true,"schema":{"type":"string","title":"Client Plant Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"title":"Body","description":"Partnerägda fält. Alla är valfria och bara de som skickas ändras. Skicka aldrig `null`, det ger 422 - utelämna fältet i stället. Ett fält som inte står här ger 403.","properties":{"battery_kw":{"description":"Batteriets effekt i kW.","examples":[5],"exclusiveMinimum":0,"title":"Battery Kw","type":"number"},"battery_kwh":{"description":"Batteriets kapacitet i kWh.","examples":[10],"exclusiveMinimum":0,"title":"Battery Kwh","type":"number"},"control_system":{"description":"Styrsystemet som styr batteriet. Valideras strikt mot listan - passar inget av värdena använd `other`.","enum":["aikion","checkwatt","emaldo","emhass","ferroamp","greenely","huawei","keepai","manual","other","pixii","reduxi","self_consumption","sigenergy","sonnen","tibber"],"examples":["other"],"title":"Control System","type":"string"},"eff":{"description":"Verkningsgrad tur och retur, större än 0 och högst 1.","examples":[0.9],"title":"Eff","exclusiveMinimum":0,"maximum":1,"type":"number"},"nameplate_kwh":{"description":"Märkkapacitet, om den skiljer sig från den levererbara kapaciteten (t.ex. vid degraderat batteri).","examples":[15],"title":"Nameplate Kwh","exclusiveMinimum":0,"type":"number"},"reserve_pct":{"description":"Andel av batteriet i procent som reserveras och inte används för optimering.","examples":[10],"title":"Reserve Pct","maximum":100,"minimum":0,"type":"number"},"zone":{"description":"Accepteras bara med samma värde som redan är lagrat (no-op). Ett ändrat värde ger 422: zonen är oföränderlig efter skapandet.","examples":["SE3"],"title":"Zone","type":"string"}}},"example":{"battery_kwh":15}}}},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PlantPatched"}}}},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Kroppen innehöll ett fält som ägs av slutkunden (ekonomi, elavtal eller betygsfönster). Inget skrevs. Partnern är alternativt avstängd.","content":{"application/json":{"example":{"detail":{"error":"field_not_partner_owned","field":"cost_sek"}}}}},"404":{"description":"Okänd `client_plant_id` för er partner. Ni ser aldrig andra partners anläggningar, så en främmande anläggning ger också 404.","content":{"application/json":{"example":{"detail":"okänd anläggning"}}}},"422":{"description":"Valideringsfel: ogiltig zon eller styrsystem, värde utanför tillåtet intervall, eller explicit `null` på ett partnerägt fält (utelämna fältet i stället för att nollställa det).","content":{"application/json":{"example":{"detail":{"error":"field_must_not_be_null","field":"battery_kwh","message":"battery_kwh får inte vara null - utelämna fältet i stället"}}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}}},"delete":{"tags":["partner"],"summary":"Radera anläggning","description":"Avvecklar en anläggning: koppling, timdata och betyg raderas, och en plats i tier-gränsen frigörs. Svarar **204** med tom kropp.\n\nRaderar en anläggning i taget. Det finns med avsikt ingen massradering av en hel flotta, som skydd mot att ett fel i en integration sopar bort all data.","operationId":"delete_plant_api_v1_partner_plants__client_plant_id__delete","security":[{"PartnerKey":[]}],"parameters":[{"name":"client_plant_id","in":"path","required":true,"schema":{"type":"string","title":"Client Plant Id"}}],"responses":{"204":{"description":"Anläggningen raderades. Tom kropp."},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Partnern är avstängd. Kontakta partner@wolta.se.","content":{"application/json":{"example":{"detail":"partnern är avstängd"}}}},"404":{"description":"Okänd `client_plant_id` för er partner. Ni ser aldrig andra partners anläggningar, så en främmande anläggning ger också 404.","content":{"application/json":{"example":{"detail":"okänd anläggning"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}}}},"/api/v1/partner/plants/{client_plant_id}/link/rotate":{"post":{"tags":["partner"],"summary":"Rotera slutkundslänk","description":"Mintar en ny `link_token` för anläggningen och returnerar den en gång. Den gamla länken slutar fungera omedelbart, och den som öppnar den möts av en sida som säger att länken inte längre gäller.\n\nDet finns bara en giltig länk-token per anläggning åt gången. Använd rotationen när en länk läckt eller när en anläggning bytt ägare.","operationId":"rotate_link_api_v1_partner_plants__client_plant_id__link_rotate_post","security":[{"PartnerKey":[]}],"parameters":[{"name":"client_plant_id","in":"path","required":true,"schema":{"type":"string","title":"Client Plant Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkRotated"}}}},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Partnern är avstängd. Kontakta partner@wolta.se.","content":{"application/json":{"example":{"detail":"partnern är avstängd"}}}},"404":{"description":"Okänd `client_plant_id` för er partner. Ni ser aldrig andra partners anläggningar, så en främmande anläggning ger också 404.","content":{"application/json":{"example":{"detail":"okänd anläggning"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}}}},"/api/v1/partner/plants/{client_plant_id}/data":{"post":{"tags":["partner"],"summary":"Skicka timdata","description":"Skickar in timdata, både för historisk backfill och löpande synk. Kroppen är ett JSON-objekt med `rows`, som måste innehålla minst en rad.\n\n`ts_utc` **måste bära tidszon**, antingen `Z` eller ett explicit offset. En naiv tidsstämpel ger 422: Wolta gissar aldrig lokaltid. Energifälten är valfria med standardvärde 0 och tillåtna värden 0–500 kWh per timme. Träffar ni taket är den vanligaste orsaken att värdet skickats i Wh i stället för kWh.\n\n`ts_utc` är timmens start på hel timme. Insättningen är en upsert på exakt tidsstämpel, så att skicka om samma fönster är riskfritt. En rad på `00:30` ersätter däremot inte raden på `00:00` utan lagras bredvid och räknas dubbelt. Högst 5 000 rader och 2 MiB per anrop (**413** över taket), och 80 000 rader per anläggning totalt.\n\nSvarets `inserted_hours`, `first` och `last` beskriver **enbart den här batchen**, inte anläggningens hela historik. `quarantined_hours` och `quarantined_rows` räknar timmar respektive rader som lagts i karantän för att de bröt mot fysikaliska eller statistiska gränser, och `repaired_battery_rows` de karantänerade rader som bar batteriflöde. Ett värde över 0 tyder på felaktig sensorkonfiguration eller ett hopp i datan.\n\nBetyg räknas inte per push: de räknas om batchat när nya priser landat.","operationId":"append_partner_data_api_v1_partner_plants__client_plant_id__data_post","security":[{"PartnerKey":[]}],"parameters":[{"name":"client_plant_id","in":"path","required":true,"schema":{"type":"string","title":"Client Plant Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataAppendResult"}}}},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Partnern är avstängd. Kontakta partner@wolta.se.","content":{"application/json":{"example":{"detail":"partnern är avstängd"}}}},"404":{"description":"Okänd `client_plant_id` för er partner. Ni ser aldrig andra partners anläggningar, så en främmande anläggning ger också 404.","content":{"application/json":{"example":{"detail":"okänd anläggning"}}}},"413":{"description":"Batchen är för stor: fler än 5 000 rader, en kropp över 2 MiB, eller anläggningens totala lagringstak (80 000 rader) nått.","content":{"application/json":{"example":{"detail":"max 5000 rader per anrop - dela upp i flera batchar"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"properties":{"rows":{"description":"Timrader, minst en och högst 5000 per anrop. Det finns ingen egen lastkolumn: förbrukningen härleds ur import, sol och batteriflöden.","items":{"properties":{"ts_utc":{"description":"Timmens starttid på hel timme, som ISO 8601 MED tidszon, antingen `Z` eller ett explicit offset. En naiv tidsstämpel ger 422 - Wolta gissar aldrig lokaltid.","examples":["2026-08-01T00:00:00Z"],"title":"Ts Utc","type":"string"},"solar_kwh":{"default":0,"description":"Solproduktion, kWh under timmen. Utelämnad lagras som 0.","maximum":500,"minimum":0,"title":"Solar Kwh","type":"number"},"grid_import_kwh":{"default":0,"description":"Köpt el, kWh under timmen. Utelämnad lagras som 0.","maximum":500,"minimum":0,"title":"Grid Import Kwh","type":"number"},"grid_export_kwh":{"default":0,"description":"Såld el, kWh under timmen. Utelämnad lagras som 0.","maximum":500,"minimum":0,"title":"Grid Export Kwh","type":"number"},"batt_charged_kwh":{"default":0,"description":"Laddat till batteriet, kWh under timmen. Utelämnad lagras som 0.","maximum":500,"minimum":0,"title":"Batt Charged Kwh","type":"number"},"batt_discharged_kwh":{"default":0,"description":"Urladdat ur batteriet, kWh under timmen. Utelämnad lagras som 0.","maximum":500,"minimum":0,"title":"Batt Discharged Kwh","type":"number"},"external_control":{"default":false,"description":"Sant om batteriet styrdes av en extern flextjänst (t.ex. Tibber Grid Rewards) under timmen. Sådana timmar neutraliseras i optimeringsbetyget i stället för att räknas som dålig prisstyrning. Utelämnad lagras som falsk.","title":"External Control","type":"boolean"}},"required":["ts_utc"],"title":"PartnerDataRow","type":"object"},"minItems":1,"title":"Rows","type":"array"}},"required":["rows"],"title":"PartnerDataPut","type":"object"},"example":{"rows":[{"ts_utc":"2026-08-01T00:00:00Z","solar_kwh":0.5,"grid_import_kwh":1,"grid_export_kwh":0.1,"batt_charged_kwh":0.2,"batt_discharged_kwh":0.2},{"ts_utc":"2026-08-01T01:00:00Z","solar_kwh":0.4,"grid_import_kwh":1.2,"grid_export_kwh":0,"batt_charged_kwh":0.1,"batt_discharged_kwh":0.3}]}}}}}},"/api/v1/partner/plants/{client_plant_id}/quarantine":{"get":{"tags":["partner"],"summary":"Timmar som inte räknas","description":"Klocktimmar i en av era anläggningar som inte räknas för att ett mätvärde inte är fysiskt möjligt. Samma svar som anläggningens ägare ser.\n\nKlocktimmar som inte räknas för att ett mätvärde inte är fysiskt möjligt, till exempel en hel mätarställning i stället för en timmes energi. Timmarna är undantagna från betyg, årsuppräkning, ekonomi och analys. Nyast först.\n\nPer timme anges de fält som bröt, värdet och taket i kWh för klocktimmen och vilket lager i regeln som fällde timmen: `A` över 200 kWh på en timme, `B` solproduktion när solen stod under horisonten i hela landet, `C` över batteriets effekt × 1,5 eller solcellernas toppeffekt × 1,3, `D` över fyra gånger anläggningens egen 99:e percentil (med ett golv per fält). `evidence` finns bara på lager C: `soc_refuted` (laddningsnivån motsäger värdet), `unsupported` (timmens övriga mätningar bär inte värdet) eller `none` (värdet går inte att bekräfta).\n\n`systematic` är sant när orimliga timmar är så många att felet ser systematiskt ut (fel enhet eller felkopplad sensor). Då läggs ingenting i karantän: timmarna räknas med, men anläggningen jämförs inte med andra. Listan är då tom.\n\nSkickas en timme igen med rättade värden bedöms den på nytt.","operationId":"plant_quarantine_api_v1_partner_plants__client_plant_id__quarantine_get","security":[{"PartnerKey":[]}],"parameters":[{"name":"client_plant_id","in":"path","required":true,"schema":{"type":"string","title":"Client Plant Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuarantineOut"}}}},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Partnern är avstängd. Kontakta partner@wolta.se.","content":{"application/json":{"example":{"detail":"partnern är avstängd"}}}},"404":{"description":"Okänd `client_plant_id` för er partner. Ni ser aldrig andra partners anläggningar, så en främmande anläggning ger också 404.","content":{"application/json":{"example":{"detail":"okänd anläggning"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}}}},"/api/v1/partner/grades":{"get":{"tags":["partner"],"summary":"Läsa betyg för flottan","description":"Senaste betyget för era anläggningar i en paginerad batch. Samma sidregler som `GET /partner/plants`: `limit` måste vara större än 0 och klipps tyst till 500.\n\n`score` är satt endast när `status` är `ok`. Övriga statusar ger `null`, inklusive `below_baseline` (styrningen presterade sämre än ett passivt batteri efter slitage). Hantera `null` som \"inget att visa än\", inte som ett fel: Wolta svarar hellre null än med ett tal som kan misstolkas.\n\n`period_start` och `period_end` beskriver all data Wolta fått inlagrad för anläggningen, inte exakt det fönster senaste beräkningen räknade på. `grade_version` visar vilken version av betygslogiken som ligger bakom siffran: jämför inte betyg över en versionsändring rakt av.","operationId":"list_grades_api_v1_partner_grades_get","security":[{"PartnerKey":[]}],"parameters":[{"name":"offset","in":"query","required":false,"schema":{"type":"integer","minimum":0,"default":0,"title":"Offset"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"default":100,"title":"Limit"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GradesPage"}}}},"401":{"description":"Saknad eller ogiltig nyckel. Kontrollera att headern är exakt `Authorization: Bearer wpk_...`.","content":{"application/json":{"example":{"detail":"Authorization: Bearer wpk_... krävs"}}}},"403":{"description":"Partnern är avstängd. Kontakta partner@wolta.se.","content":{"application/json":{"example":{"detail":"partnern är avstängd"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Rate-budgeten är förbrukad. `Retry-After` anger antal sekunder att vänta.","content":{"application/json":{"example":{"detail":"partner-budgeten är slut, försök strax"}}}}}}},"/api/v1/{connector}/connect":{"post":{"tags":["integrationer"],"summary":"Starta koppling mot leverantören","description":"Startar inloggningen hos leverantörens moln och svarar med adressen webbläsaren ska skickas till. Svaret sätter en kortlivad kopplingskaka; 404 om kopplingen inte är aktiverad, 429 vid för många anrop.","operationId":"start_connect_api_v1__connector__connect_post","parameters":[{"name":"connector","in":"path","required":true,"schema":{"type":"string","title":"Connector"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Start Connect Api V1  Connector  Connect Post"}}}},"401":{"description":"Leverantören kräver ett inloggat konto. Logga in och försök igen."},"404":{"description":"Kopplingen finns inte eller är inte aktiverad."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"För många anrop från samma klient. Vänta en stund."}}}},"/api/v1/{connector}/callback":{"get":{"tags":["integrationer"],"summary":"Återvändo från leverantören","description":"Tar emot leverantörens svar efter att ägaren godkänt, hämtar ägarens anläggningar och skickar vidare till valsidan. Svarar alltid med en omdirigering. 404 om kopplingen inte är aktiverad.","operationId":"callback_api_v1__connector__callback_get","parameters":[{"name":"connector","in":"path","required":true,"schema":{"type":"string","title":"Connector"}},{"name":"code","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Code"}},{"name":"state","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"State"}},{"name":"error","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error"}}],"responses":{"302":{"description":"Lyckat svar.","content":{"application/json":{"schema":{}}}},"404":{"description":"Kopplingen finns inte eller är inte aktiverad."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/{connector}/connect/session":{"get":{"tags":["integrationer"],"summary":"Pågående kopplings status","description":"Anläggningarna som ägaren godkänt, med elområdesledtråd och vad som hittades på varje anläggning. 404 när ingen koppling pågår.","operationId":"connect_session_api_v1__connector__connect_session_get","parameters":[{"name":"connector","in":"path","required":true,"schema":{"type":"string","title":"Connector"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connect Session Api V1  Connector  Connect Session Get"}}}},"404":{"description":"Ingen pågående koppling."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/{connector}/connect/signup":{"post":{"tags":["integrationer"],"summary":"Skapa konto för kopplingen","description":"För leverantörer där kopplingen kräver ett Wolta-konto. Skickar en länk till e-postadressen; finns inget konto skapas ett. Länken leder tillbaka till kopplingssidan. Svarar alltid **202**, även för kända adresser: ett annat svar hade avslöjat vilka adresser som har konto.\n\nKräver en giltig Turnstile-token. Vägen är byggd för webbläsaren, inte för maskinell användning.","operationId":"connect_signup_api_v1__connector__connect_signup_post","parameters":[{"name":"connector","in":"path","required":true,"schema":{"type":"string","title":"Connector"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectSignupIn"}}}},"responses":{"202":{"description":"Begäran är mottagen och köad. Resultatet hämtas genom att polla.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connect Signup Api V1  Connector  Connect Signup Post"}}}},"404":{"description":"Kopplingen finns inte, är inte aktiverad eller kräver inget konto."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/{connector}/connect/form":{"post":{"tags":["integrationer"],"summary":"Koppla med serienummer och kod","description":"För leverantörer där ägaren kopplar med växelriktarens serienummer och verifieringskod i stället för att logga in hos leverantören. Kräver inloggat konto och uttryckligt samtycke. Svarar med sidan för steg 2 och sätter en kortlivad kopplingskaka.","operationId":"connect_form_api_v1__connector__connect_form_post","parameters":[{"name":"connector","in":"path","required":true,"schema":{"type":"string","title":"Connector"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connect Form Api V1  Connector  Connect Form Post"}}}},"401":{"description":"Inte inloggad."},"404":{"description":"Kopplingen finns inte, är inte aktiverad eller kopplas på annat sätt."},"409":{"description":"Anläggningen är redan kopplad till ett annat konto."},"422":{"description":"Samtycke saknas, uppgifterna hör inte ihop, eller anläggningen saknar elmätare."},"429":{"description":"För många försök. Försök igen i morgon."},"503":{"description":"Leverantören är upptagen eller svarar inte. Försök igen om en minut. Med `reason: config` är felet Woltas egen inställning, inte leverantörens. Med `reason: refused` svarade leverantören och nekade kopplingen med en felkod Wolta inte känner; `code` bär koden när den har formen av en felkod."}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Serienummer och kod från växelriktarens märkskylt, plus samtycket till vad kopplingen ger.","properties":{"sn":{"description":"Växelriktarens serienummer, som det står på märkskylten.","maxLength":40,"minLength":1,"title":"Sn","type":"string"},"check_code":{"description":"Verifieringskoden från märkskylten eller leverantörens app. Används bara för kopplingen och sparas aldrig.","maxLength":20,"minLength":1,"title":"Check Code","type":"string"},"consent":{"description":"Ägarens samtycke till vad kopplingen ger Wolta rätt till.","title":"Consent","type":"boolean"}},"required":["sn","check_code","consent"],"title":"ConnectFormIn","type":"object"},"example":{"sn":"A1B2C3D4E5F6G7H8","check_code":"123456","consent":true}}}}}},"/api/v1/{connector}/connect/plant":{"post":{"tags":["integrationer"],"summary":"Koppla vald anläggning","description":"Skapar anläggningen i Wolta och startar hämtningen av historiken. Elområde och styrsystem (det som styr batteriet) måste anges (422 annars), och en anläggning utan elmätare kan inte kopplas (422). Batteriuppgifter är valfria – utan dem registreras anläggningen som solcellsanläggning utan batteri. För kopplingar med serienummer väljer ägaren hur långt bak historiken hämtas: hela historiken eller från och med ett datum, högst 730 dygn bak (422 annars). 409 om anläggningen hör till ett annat konto, 404 när kopplingssessionen gått ut.","operationId":"connect_plant_api_v1__connector__connect_plant_post","parameters":[{"name":"connector","in":"path","required":true,"schema":{"type":"string","title":"Connector"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConnectPlantIn"}}}},"responses":{"201":{"description":"Resursen skapades.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connect Plant Api V1  Connector  Connect Plant Post"}}}},"401":{"description":"Leverantören kräver ett inloggat konto. Logga in och försök igen."},"403":{"description":"Kopplingen startades av ett annat konto."},"404":{"description":"Ingen pågående koppling."},"409":{"description":"Anläggningen är redan kopplad till ett annat konto."},"422":{"description":"Elområde, styrsystem eller historikval saknas eller är ogiltigt, eller anläggningen saknar elmätare."}}}},"/api/v1/{connector}/status":{"get":{"tags":["integrationer"],"summary":"Kopplingens status","description":"Hur långt hämtningen kommit, när den senast kördes och vad som ser tveksamt ut i datan. 401 utan giltig token, 404 när anläggningen saknar kopplingen.","operationId":"connector_status_api_v1__connector__status_get","security":[{"ProfileToken":[]}],"parameters":[{"name":"connector","in":"path","required":true,"schema":{"type":"string","title":"Connector"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Connector Status Api V1  Connector  Status Get"}}}},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/{connector}/binding":{"delete":{"tags":["integrationer"],"summary":"Koppla från leverantören","description":"Avslutar hämtningen och släpper kopplingen hos leverantören. Den lagrade nyckeln ligger krypterad kvar hos Wolta enbart så länge frånkopplingen hos leverantören inte bekräftats, och raderas därefter. Redan hämtad data ligger kvar. 401 utan giltig token, 404 utan koppling.","operationId":"connector_detach_api_v1__connector__binding_delete","security":[{"ProfileToken":[]}],"parameters":[{"name":"connector","in":"path","required":true,"schema":{"type":"string","title":"Connector"}}],"responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Saknad eller ogiltig `Authorization: Bearer`-header."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/link":{"post":{"tags":["konto"],"summary":"Koppla e-post till anläggning","description":"Skickar en bekräftelselänk som kopplar en e-postadress till anläggningen bakom en profil-token, eller till anläggningen bakom en kopplingskod från Home Assistant-integrationen - ange exakt en av dem. Svarar **202** när mailet går iväg, oavsett om adressen redan finns som konto, så att svaret inte avslöjar vilka adresser som har konto. Ett okänt profil-token, eller en ogiltig, utgången eller redan förbrukad kopplingskod, ger i stället 400, och för många kodförsök från samma klient ger 429.\n\nKräver en giltig Turnstile-token. Vägen är byggd för webbläsaren, inte för maskinell användning.","operationId":"link_api_v1_account_link_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LinkIn"}}},"required":true},"responses":{"202":{"description":"Begäran är mottagen och köad. Resultatet hämtas genom att polla.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Link Api V1 Account Link Post"}}}},"400":{"description":"Ogiltig, utgången eller redan förbrukad claim_code, eller okänt profile_token."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"För många kodförsök från samma klient. Vänta en minut."}}}},"/api/v1/account/login":{"post":{"tags":["konto"],"summary":"Begär inloggningslänk","description":"Skickar en engångslänk för inloggning till en e-postadress. Svarar alltid **202**, även för okända adresser: ett annat svar hade avslöjat vilka adresser som har konto. Ett konto utan någon anläggning kan alltså inte skapas den här vägen.\n\nKräver en giltig Turnstile-token. Vägen är byggd för webbläsaren, inte för maskinell användning.","operationId":"login_api_v1_account_login_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/LoginIn"}}},"required":true},"responses":{"202":{"description":"Begäran är mottagen och köad. Resultatet hämtas genom att polla.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Login Api V1 Account Login Post"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/confirm":{"post":{"tags":["konto"],"summary":"Lös in inloggningslänk","description":"Löser in engångstoken från e-postlänken och sätter sessionskakan. Token är kortlivad och kan bara användas en gång.","operationId":"confirm_api_v1_account_confirm_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmIn"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Confirm Api V1 Account Confirm Post"}}}},"400":{"description":"Länken gick inte att lösa in. `reason` säger varför: `expired` (gått ut), `used` (redan använd) eller `unknown`. `next` anger var en ny länk begärs, när länken skapades på en sådan sida."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/me":{"get":{"tags":["konto"],"summary":"Kontots översikt","description":"Kontots e-postadress, kopplade anläggningar och inställningar. Kräver giltig sessionskaka; 401 annars.","operationId":"me_api_v1_account_me_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Me Api V1 Account Me Get"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."}},"security":[{"Session":[]}]},"delete":{"tags":["konto"],"summary":"Radera kontot","description":"Raderar kontot och kopplingarna till dess anläggningar. Leverantörskopplingar som kräver konto kopplas bort hos leverantören. Anläggningarnas egna data raderas separat via anläggningsvägarna.","operationId":"delete_me_api_v1_account_me_delete","responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."}},"security":[{"Session":[]}]}},"/api/v1/account/profiles":{"post":{"tags":["konto"],"summary":"Koppla anläggning till kontot","description":"Kopplar en befintlig anläggning till det inloggade kontot med anläggningens profil-token som bevis på innehav. Ogiltig token ger 400.","operationId":"add_profile_api_v1_account_profiles_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileIn"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Add Profile Api V1 Account Profiles Post"}}}},"400":{"description":"Ogiltig profil-token - anläggningen kunde inte kopplas."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"Session":[]}]}},"/api/v1/account/profiles/claim":{"post":{"tags":["konto"],"summary":"Koppla anläggning med kod","description":"Kopplar anläggningen till kontot med en kopplingskod skapad från Home Assistant-integrationen. Koden gäller i 10 minuter och bara en gång. Okänd, utgången och redan använd kod ger samma svar.","operationId":"claim_profile_api_v1_account_profiles_claim_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClaimIn"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Claim Profile Api V1 Account Profiles Claim Post"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"Session":[]}]}},"/api/v1/account/profiles/{submission_id}":{"delete":{"tags":["konto"],"summary":"Koppla loss anläggning","description":"Tar bort kopplingen mellan kontot och anläggningen. Anläggningen och dess data finns kvar och nås fortfarande med profil-token. En leverantörskoppling som kräver konto kopplas bort hos leverantören.","operationId":"delete_profile_api_v1_account_profiles__submission_id__delete","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/prefs":{"put":{"tags":["konto"],"summary":"Spara aviseringsval","description":"Sätter kontots aviseringsinställningar. Okänd preferenstyp ger 422.","operationId":"put_prefs_api_v1_account_prefs_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PrefIn"}}},"required":true},"responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"Session":[]}]}},"/api/v1/account/unsubscribe":{"get":{"tags":["konto"],"summary":"Avregistreringssidan","description":"Skickar vidare till den mänskliga avregistreringssidan med token bevarad. Finns för att e-postklienter och länkförhandsvisare som GET:ar avregistreringslänken ska mötas av en sida i stället för 405.","operationId":"unsubscribe_landing_api_v1_account_unsubscribe_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{}}}},"307":{"description":"Vidarebefordran till den mänskliga avregistreringssidan."}}},"post":{"tags":["konto"],"summary":"Avregistrera utskick","description":"Stänger av en utskickstyp. Hela auktoriseringen ligger i den signerade token från mejlet, ingen inloggning krävs. Stöder både RFC 8058:s ett-klick-avregistrering (som e-postklienter anropar automatiskt) och den mänskliga avregistreringssidan. Det är alltid den signerade utskickstypen i token som avgör vad som stängs av, aldrig ett fält i anropet.","operationId":"unsubscribe_api_v1_account_unsubscribe_post","responses":{"204":{"description":"Lyckat svar, tom kropp."}}}},"/api/v1/account/logout":{"post":{"tags":["konto"],"summary":"Logga ut","description":"Återkallar den aktuella sessionen på servern. En redan kopierad sessionskaka slutar därmed också fungera.","operationId":"logout_api_v1_account_logout_post","responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."}},"security":[{"Session":[]}]}},"/api/v1/account/logout-all":{"post":{"tags":["konto"],"summary":"Logga ut överallt","description":"Återkallar kontots samtliga sessioner. Rör inte anläggningar som strömmar data, de autentiseras med token och påverkas inte.","operationId":"logout_all_api_v1_account_logout_all_post","responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."}},"security":[{"Session":[]}]}},"/api/v1/account/sessions":{"get":{"tags":["konto"],"summary":"Inloggade enheter","description":"Kontots aktiva sessioner med enhet och senaste användning, för enhetslistan på kontosidan.","operationId":"list_sessions_api_v1_account_sessions_get","responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"items":{"additionalProperties":true,"type":"object"},"type":"array","title":"Response List Sessions Api V1 Account Sessions Get"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."}},"security":[{"Session":[]}]}},"/api/v1/account/sessions/{session_id}":{"delete":{"tags":["konto"],"summary":"Återkalla session","description":"Återkallar en enskild session. Okänd session och någon annans session ger båda 404, så svaret avslöjar inte vilka sessioner som finns. Den egna aktuella sessionen får återkallas: nästa anrop svarar då 401.","operationId":"revoke_session_api_v1_account_sessions__session_id__delete","security":[{"Session":[]}],"parameters":[{"name":"session_id","in":"path","required":true,"schema":{"type":"integer","title":"Session Id"}}],"responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Okänd session, eller någon annans. Samma svar i båda fallen."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}":{"get":{"tags":["konto"],"summary":"Anläggningens parametrar (inloggad)","description":"Samma svar som `GET /profile`, för en anläggning kontot äger. Autentiseras med sessionskakan i stället för token. Okänd och främmande anläggning ger båda 404.","operationId":"get_plant_api_v1_account_plant__submission_id__get","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Get Plant Api V1 Account Plant  Submission Id  Get"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["konto"],"summary":"Uppdatera anläggningen (inloggad)","description":"Samma semantik som `PATCH /profile`, för en anläggning kontot äger.","operationId":"patch_plant_api_v1_account_plant__submission_id__patch","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfilePatch"}}}},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Patch Plant Api V1 Account Plant  Submission Id  Patch"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["konto"],"summary":"Radera anläggningen (inloggad)","description":"Raderar anläggningen och all dess data. Kan inte ångras.","operationId":"delete_plant_api_v1_account_plant__submission_id__delete","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/recompute":{"post":{"tags":["konto"],"summary":"Begär omräkning (inloggad)","description":"Samma semantik som `POST /profile/recompute`, för en anläggning kontot äger. Svarar 202.","operationId":"recompute_plant_api_v1_account_plant__submission_id__recompute_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"202":{"description":"Begäran är mottagen och köad. Resultatet hämtas genom att polla.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Recompute Plant Api V1 Account Plant  Submission Id  Recompute Post"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"429":{"description":"Omräkningen har redan körts inom cooldownen. `Retry-After` anger när nästa är tillåten."}}}},"/api/v1/account/plant/{submission_id}/warm":{"get":{"tags":["konto"],"summary":"Status för köad beräkning (inloggad)","description":"Samma status som `GET /warm`, för en anläggning kontot äger.","operationId":"warm_plant_api_v1_account_plant__submission_id__warm_get","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Warm Plant Api V1 Account Plant  Submission Id  Warm Get"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/analysis":{"get":{"tags":["konto"],"summary":"Analys av styrningen (inloggad)","description":"Samma svar som `GET /analysis`, för en anläggning kontot äger.","operationId":"analysis_plant_api_v1_account_plant__submission_id__analysis_get","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}},{"name":"view","in":"query","required":false,"schema":{"enum":["full","status"],"type":"string","description":"`full` (standard) ger hela svaret, `status` bara status och förlopp för pollning.","default":"full","title":"View"},"description":"`full` (standard) ger hela svaret, `status` bara status och förlopp för pollning."}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Analysis Plant Api V1 Account Plant  Submission Id  Analysis Get"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"`view` är varken `full` eller `status`. Ett anläggnings-id som inte är ett heltal ger också 422."}}}},"/api/v1/account/plant/{submission_id}/analysis/intervals":{"get":{"tags":["konto"],"summary":"Analysens intervall (inloggad)","description":"Samma svar och samma gränser som `GET /analysis/intervals`, för en anläggning kontot äger.","operationId":"analysis_intervals_plant_api_v1_account_plant__submission_id__analysis_intervals_get","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}},{"name":"from","in":"query","required":true,"schema":{"type":"string","format":"date","title":"From"}},{"name":"to","in":"query","required":true,"schema":{"type":"string","format":"date","title":"To"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Analysis Intervals Plant Api V1 Account Plant  Submission Id  Analysis Intervals Get"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Spannet är ogiltigt: `from` ligger efter `to`, spannet överstiger 31 dygn, eller ett datum saknas eller är inte ett giltigt datum. Ett anläggnings-id som inte är ett heltal ger också 422."}}}},"/api/v1/account/plant/{submission_id}/quarantine":{"get":{"tags":["konto"],"summary":"Timmar som inte räknas (inloggad)","description":"Samma svar som `GET /quarantine`, för en anläggning kontot äger.","operationId":"quarantine_plant_api_v1_account_plant__submission_id__quarantine_get","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/QuarantineOut"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/token":{"post":{"tags":["konto"],"summary":"Ny profil-token","description":"Mintar en färsk profil-token för en anläggning kontot äger. Den visas **en gång**: Wolta lagrar bara ett hashat värde och kan aldrig visa en tappad token igen.\n\nBehövs för att koppla Home Assistant-integrationen, som autentiseras med token även när ägaren är inloggad. Den gamla token slutar fungera.","operationId":"issue_plant_token_api_v1_account_plant__submission_id__token_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Issue Plant Token Api V1 Account Plant  Submission Id  Token Post"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/share":{"post":{"tags":["konto"],"summary":"Skapa delningslänk (inloggad)","description":"Skapar en delbar länk till anläggningens betyg. `wear_on` styr om slitage räknas in i den delade vyn. Svarar 201.","operationId":"share_plant_api_v1_account_plant__submission_id__share_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShareIn"}}}},"responses":{"201":{"description":"Resursen skapades.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Share Plant Api V1 Account Plant  Submission Id  Share Post"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/sizing":{"post":{"tags":["konto"],"summary":"Optimal batteristorlek (inloggad)","description":"Samma beräkning som `POST /sizing`, för en anläggning kontot äger.","operationId":"sizing_plant_api_v1_account_plant__submission_id__sizing_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SizingIn"}}}},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sizing Plant Api V1 Account Plant  Submission Id  Sizing Post"}}}},"202":{"description":"Beräkningen är köad (kall cache). Svaret bär `warm.config_key` som pollas via `GET /warm/by-config`; gör sedan om anropet för att hämta resultatet."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/simulate":{"post":{"tags":["konto"],"summary":"Hushållsekonomi (inloggad)","description":"Samma beräkning som `GET /simulate/household`, för en anläggning kontot äger.","operationId":"simulate_plant_api_v1_account_plant__submission_id__simulate_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SimulateIn"}}}},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Simulate Plant Api V1 Account Plant  Submission Id  Simulate Post"}}}},"202":{"description":"Beräkningen är köad (kall cache). Svaret bär `warm.config_key` som pollas via `GET /warm/by-config`; gör sedan om anropet för att hämta resultatet."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/sonnen":{"get":{"tags":["konto"],"summary":"Sonnen-kopplingens status","description":"Visar om anläggningen tar emot data från ett sonnenBatterie och när senaste webhooken kom in.","operationId":"sonnen_status_api_v1_account_plant__submission_id__sonnen_get","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sonnen Status Api V1 Account Plant  Submission Id  Sonnen Get"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["konto"],"summary":"Koppla från sonnenBatterie","description":"Kopplar bort batteriet. Redan inlagrad data ligger kvar, men ingen ny tas emot.","operationId":"sonnen_detach_api_v1_account_plant__submission_id__sonnen_delete","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sonnen Detach Api V1 Account Plant  Submission Id  Sonnen Delete"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/sonnen/attach":{"post":{"tags":["konto"],"summary":"Koppla sonnenBatterie","description":"Skapar webhook-adressen som batteriet ska posta till. Ingest-token visas **en gång** och lagras hashat.","operationId":"sonnen_attach_api_v1_account_plant__submission_id__sonnen_attach_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sonnen Attach Api V1 Account Plant  Submission Id  Sonnen Attach Post"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/sonnen/rotate":{"post":{"tags":["konto"],"summary":"Rotera Sonnen-token","description":"Mintar en ny ingest-token för webhooken. Den gamla slutar fungera omedelbart, så batteriets inställningar måste uppdateras.","operationId":"sonnen_rotate_api_v1_account_plant__submission_id__sonnen_rotate_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Sonnen Rotate Api V1 Account Plant  Submission Id  Sonnen Rotate Post"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/connector":{"get":{"tags":["konto"],"summary":"Kopplingens status (inloggad)","description":"Samma status som token-vägen, för en anläggning kontot äger.","operationId":"plant_connector_status_api_v1_account_plant__submission_id__connector_get","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Plant Connector Status Api V1 Account Plant  Submission Id  Connector Get"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["konto"],"summary":"Koppla från leverantören (inloggad)","description":"Avslutar hämtningen och släpper kopplingen hos leverantören. Den lagrade nyckeln ligger krypterad kvar hos Wolta enbart så länge frånkopplingen hos leverantören inte bekräftats, och raderas därefter. Redan hämtad data ligger kvar.","operationId":"plant_connector_detach_api_v1_account_plant__submission_id__connector_delete","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/link":{"post":{"tags":["konto"],"summary":"Hämta eller skapa läslänk (inloggad)","description":"Som `POST /profile/{token}/link`, för en anläggning kontot äger. Autentiseras med sessionskakan.","operationId":"mint_link_session_api_v1_account_plant__submission_id__link_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Mint Link Session Api V1 Account Plant  Submission Id  Link Post"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"503":{"description":"Länkfunktionen är inte aktiverad på servern (krypteringsnyckel saknas)."}}},"delete":{"tags":["konto"],"summary":"Ta bort läslänk (inloggad)","description":"Som `DELETE /profile/{token}/link`, för en anläggning kontot äger.","operationId":"revoke_link_session_api_v1_account_plant__submission_id__link_delete","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"204":{"description":"Lyckat svar, tom kropp."},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/v1/account/plant/{submission_id}/link/rotate":{"post":{"tags":["konto"],"summary":"Byt läslänk (inloggad)","description":"Som `POST /profile/{token}/link/rotate`, för en anläggning kontot äger.","operationId":"rotate_link_session_api_v1_account_plant__submission_id__link_rotate_post","security":[{"Session":[]}],"parameters":[{"name":"submission_id","in":"path","required":true,"schema":{"type":"integer","title":"Submission Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Rotate Link Session Api V1 Account Plant  Submission Id  Link Rotate Post"}}}},"401":{"description":"Ingen giltig session. Logga in på nytt."},"404":{"description":"Anläggningen finns inte, eller ägs av någon annan. Samma svar i båda fallen - svaret avslöjar aldrig vad som finns."},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}},"503":{"description":"Länkfunktionen är inte aktiverad på servern (krypteringsnyckel saknas)."}}}},"/b/{share_id}":{"get":{"tags":["delning"],"summary":"Delad betygssida","description":"Den publika sidan bakom en delningslänk. Renderar HTML, inte JSON, och kräver ingen autentisering: den som har länken kommer åt vyn.","operationId":"share_html_b__share_id__get","parameters":[{"name":"share_id","in":"path","required":true,"schema":{"type":"string","title":"Share Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"text/html":{"schema":{"type":"string"}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/b/{share_id}/og.png":{"get":{"tags":["delning"],"summary":"Förhandsbild för delningslänk","description":"PNG-bilden som visas när en delningslänk klistras in i sociala medier eller chattar.","operationId":"share_og_png_b__share_id__og_png_get","parameters":[{"name":"share_id","in":"path","required":true,"schema":{"type":"string","title":"Share Id"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{}}}},"422":{"description":"Valideringsfel: ett fält saknas, har fel typ eller ligger utanför tillåtet intervall. Kroppen pekar ut vilket fält det gäller.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}}},"components":{"schemas":{"AdoptRequest":{"properties":{"client_plant_id":{"anyOf":[{"type":"string","maxLength":200,"minLength":16},{"type":"null"}],"title":"Client Plant Id"}},"type":"object","title":"AdoptRequest"},"BatteryStateRow":{"properties":{"unit":{"type":"string","maxLength":128,"minLength":1,"title":"Unit","description":"Klientens id för batterienheten, till exempel sensorns entity_id. Lagras aldrig i klartext."},"ts":{"type":"string","format":"date-time","title":"Ts","description":"Intervallets start. Tidszonsmedveten och jämnt delbar med period_s."},"period_s":{"type":"integer","enum":[900,3600],"title":"Period S","description":"Intervallets längd i sekunder: 900 (kvart) eller 3600 (timme)."},"soc_mean":{"anyOf":[{"type":"number","maximum":100,"minimum":0},{"type":"null"}],"title":"Soc Mean","description":"Tidsviktat medel av laddningsnivån i procent."},"soc_min":{"anyOf":[{"type":"number","maximum":100,"minimum":0},{"type":"null"}],"title":"Soc Min","description":"Lägsta laddningsnivå i procent, inklusive värdet vid intervallets start."},"soc_max":{"anyOf":[{"type":"number","maximum":100,"minimum":0},{"type":"null"}],"title":"Soc Max","description":"Högsta laddningsnivå i procent, inklusive värdet vid intervallets start."},"soh_pct":{"anyOf":[{"type":"number","maximum":110,"minimum":0},{"type":"null"}],"title":"Soh Pct","description":"Batteriets hälsotal i procent enligt batteriet, tidsviktat medel."},"bms_capacity_kwh":{"anyOf":[{"type":"number","maximum":1000,"exclusiveMinimum":0},{"type":"null"}],"title":"Bms Capacity Kwh","description":"Batteriets egen uppgift om full kapacitet i kWh, tidsviktat medel."},"soc_max_gap_s":{"anyOf":[{"type":"integer","maximum":86400,"minimum":0},{"type":"null"}],"title":"Soc Max Gap S","description":"Största avståndet i sekunder mellan på varandra följande SoC-avläsningar som intervallet bygger på, inklusive från sista avläsningen till intervallets slut. Utelämnas när det inte är känt."}},"type":"object","required":["unit","ts","period_s"],"title":"BatteryStateRow"},"BatteryStateSource":{"properties":{"unit":{"type":"string","maxLength":128,"minLength":1,"title":"Unit","description":"Samma id som i battery_state."},"source":{"type":"string","maxLength":200,"minLength":1,"title":"Source","description":"Var värdet kommer ifrån, till exempel ha:<plattform>:<entity_id>."},"semantics":{"type":"string","enum":["bms","user","unknown"],"title":"Semantics","description":"bms om laddningsnivån är batterisystemets egen, user om den är skalad till det användbara fönstret, annars unknown.","default":"unknown"}},"type":"object","required":["unit","source"],"title":"BatteryStateSource"},"Body_compute_api_v1_calibration_compute_post":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"},"zone":{"type":"string","title":"Zone"},"has_battery":{"type":"boolean","title":"Has Battery","description":"Styr hur uppladdningen valideras och om batterimetrik räknas. Lagrad batteriflagga härleds ur battery_kwh/battery_kw: med has_battery=false lagras inga batterivärden, även om de skickas.","default":false},"has_solar":{"type":"boolean","title":"Has Solar","default":false},"battery_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kwh"},"battery_kw":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kw"},"eff":{"type":"number","title":"Eff","default":0.9},"house_type":{"type":"string","title":"House Type","default":"heated"},"control_system":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Control System"},"control_system_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Control System Name"},"pv_kwp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pv Kwp"},"cost_sek":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost Sek"},"purchase_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"},"profile_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Token"},"store":{"type":"boolean","title":"Store","default":false}},"type":"object","required":["zone"],"title":"Body_compute_api_v1_calibration_compute_post"},"Body_grade_api_v1_grade_post":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"},"zone":{"type":"string","title":"Zone"},"battery_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kwh"},"battery_kw":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kw"},"nameplate_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Nameplate Kwh"},"nameplate_kw":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Nameplate Kw"},"battery_declared":{"type":"boolean","title":"Battery Declared","default":false},"eff":{"type":"number","title":"Eff","default":0.9},"contribute_score":{"type":"boolean","title":"Contribute Score","default":true},"share_profile":{"type":"boolean","title":"Share Profile","default":false},"control_system":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Control System"},"control_system_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Control System Name"},"profile_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Token"},"dedup_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dedup Token"},"cost_sek":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost Sek"},"purchase_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"},"purchase_date_solar":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date Solar"},"purchase_date_battery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date Battery"},"paid_solar":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Paid Solar"},"paid_battery":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Paid Battery"},"pv_kwp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pv Kwp"},"sensor_ids":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sensor Ids"},"dedup":{"type":"boolean","title":"Dedup","default":false},"purchase_motivation":{"items":{"type":"string"},"type":"array","title":"Purchase Motivation","default":[]},"purchase_motivation_note":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Motivation Note"},"grid_var_ore":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Grid Var Ore"},"surcharge_ore":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Surcharge Ore"},"export_extra_ore":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Export Extra Ore"},"grid_var_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Grid Var Pct"},"export_extra_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Export Extra Pct"}},"type":"object","required":["zone"],"title":"Body_grade_api_v1_grade_post"},"Body_sizing_endpoint_api_v1_sizing_post":{"properties":{"file":{"anyOf":[{"type":"string","contentMediaType":"application/octet-stream"},{"type":"null"}],"title":"File"},"zone":{"type":"string","title":"Zone"},"battery_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kwh"},"battery_kw":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kw"},"eff":{"type":"number","title":"Eff","default":0.9},"kr_per_kwh":{"type":"number","title":"Kr Per Kwh","default":7000},"expansion_kr_per_kwh":{"type":"number","title":"Expansion Kr Per Kwh","default":3500},"max_cycles":{"anyOf":[{"type":"number","maximum":15000,"minimum":2000},{"type":"null"}],"title":"Max Cycles"},"calendar_years":{"anyOf":[{"type":"integer","maximum":40,"minimum":1},{"type":"null"}],"title":"Calendar Years"},"battery_degradation":{"anyOf":[{"type":"number","maximum":0.2,"minimum":0},{"type":"null"}],"title":"Battery Degradation"},"kw_per_kwh":{"type":"number","title":"Kw Per Kwh","default":0.5},"green_mode":{"type":"string","title":"Green Mode","default":"off"},"persons":{"type":"integer","maximum":10,"minimum":1,"title":"Persons","default":1},"realistic":{"type":"boolean","title":"Realistic","default":true},"capture":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Capture"},"profile_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Token"},"cabinet_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cabinet Kwh"},"cabinet_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cabinet Cost"},"inverter_cost":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Inverter Cost"},"mode":{"type":"string","title":"Mode","default":"capacity"}},"type":"object","required":["zone"],"title":"Body_sizing_endpoint_api_v1_sizing_post"},"CheckPlantIn":{"properties":{"sensor_ids":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sensor Ids"},"zone":{"type":"string","title":"Zone","default":""},"dedup_token":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Dedup Token"}},"type":"object","title":"CheckPlantIn"},"ClaimIn":{"properties":{"code":{"type":"string","maxLength":64,"minLength":1,"title":"Code","description":"Kopplingskoden, med eller utan bindestreck."}},"type":"object","required":["code"],"title":"ClaimIn"},"ConfirmIn":{"properties":{"jti":{"type":"string","title":"Jti"}},"type":"object","required":["jti"],"title":"ConfirmIn"},"ConnectPlantIn":{"properties":{"external_id":{"type":"string","maxLength":200,"minLength":1,"title":"External Id"},"zone":{"type":"string","title":"Zone"},"control_system":{"type":"string","maxLength":40,"minLength":1,"title":"Control System"},"control_system_name":{"anyOf":[{"type":"string","maxLength":100},{"type":"null"}],"title":"Control System Name"},"battery_kwh":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Battery Kwh"},"battery_kw":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Battery Kw"},"eff":{"type":"number","maximum":1,"exclusiveMinimum":0,"title":"Eff","default":0.9},"has_solar":{"type":"boolean","title":"Has Solar","default":false},"pv_kwp":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Pv Kwp"},"cost_sek":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"title":"Cost Sek"},"purchase_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"},"history_from":{"anyOf":[{"type":"string","maxLength":10},{"type":"null"}],"title":"History From"}},"additionalProperties":false,"type":"object","required":["external_id","zone","control_system"],"title":"ConnectPlantIn","description":"Fälten kopplingsflödet stödjer: samma anläggningsuppgifter som guiden, plus valet av leverantörens anläggning."},"ConnectSignupIn":{"properties":{"email":{"type":"string","maxLength":200,"title":"Email"},"turnstile_token":{"type":"string","title":"Turnstile Token"}},"type":"object","required":["email","turnstile_token"],"title":"ConnectSignupIn"},"DataAppendResult":{"properties":{"inserted_hours":{"type":"integer","title":"Inserted Hours","description":"Antal rader i DENNA batch, inte anläggningens hela historik.","examples":[2]},"first":{"type":"string","title":"First","description":"Första tidsstämpeln i denna batch."},"last":{"type":"string","title":"Last","description":"Sista tidsstämpeln i denna batch."},"repaired_battery_rows":{"type":"integer","title":"Repaired Battery Rows","description":"Antal rader i batchens timmar som lagts i karantän och bar batteriflöde. Över 0 tyder på felaktig sensorkonfiguration eller ett hopp i er data.","examples":[0]},"quarantined_hours":{"type":"integer","title":"Quarantined Hours","description":"Antal klocktimmar i batchen som lagts i karantän för att något fält bröt mot fysikaliska eller statistiska gränser. Timmarna räknas inte i betyget.","examples":[0]},"quarantined_rows":{"type":"integer","title":"Quarantined Rows","description":"Antal lagrade rader i de karantänerade timmarna.","examples":[0]}},"type":"object","required":["inserted_hours","first","last","repaired_battery_rows","quarantined_hours","quarantined_rows"],"title":"DataAppendResult"},"DataPut":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/DataRow"},"type":"array","maxItems":40000,"minItems":1,"title":"Rows"},"battery_state":{"items":{"$ref":"#/components/schemas/BatteryStateRow"},"type":"array","maxItems":40000,"title":"Battery State","description":"Valfri laddningsnivå per batterienhet och intervall. Samlas in för att senare kunna mäta batteriets kapacitet. Påverkar inte betyget."},"battery_sources":{"items":{"$ref":"#/components/schemas/BatteryStateSource"},"type":"array","maxItems":16,"title":"Battery Sources","description":"Källan för varje enhet i battery_state. Krävs första gången en enhet skickas."}},"type":"object","required":["rows"],"title":"DataPut"},"DataRow":{"properties":{"ts":{"type":"string","format":"date-time","title":"Ts"},"batt_charged_kwh":{"type":"number","maximum":500,"minimum":0,"title":"Batt Charged Kwh"},"batt_discharged_kwh":{"type":"number","maximum":500,"minimum":0,"title":"Batt Discharged Kwh"},"solar_kwh":{"type":"number","maximum":500,"minimum":0,"title":"Solar Kwh","default":0},"grid_import_kwh":{"type":"number","maximum":500,"minimum":0,"title":"Grid Import Kwh","default":0},"grid_export_kwh":{"type":"number","maximum":500,"minimum":0,"title":"Grid Export Kwh","default":0},"external_control":{"type":"boolean","title":"External Control","description":"Sant om batteriet styrdes av en extern flextjänst (t.ex. Tibber Grid Rewards) under timmen. Sådana timmar neutraliseras i optimeringsbetyget i stället för att räknas som dålig prisstyrning. Utelämnad lagras som falsk.","default":false}},"type":"object","required":["ts","batt_charged_kwh","batt_discharged_kwh"],"title":"DataRow"},"GradeRow":{"properties":{"client_plant_id":{"type":"string","title":"Client Plant Id"},"score":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Score","description":"Optimeringsbetyget. Satt ENDAST när `status` är `ok`; alla andra statusar ger `null`. Hantera null som \"inget att visa än\", inte som ett fel.","examples":[62]},"status":{"type":"string","enum":["none","collecting","check_data","below_baseline","ok"],"title":"Status","description":"Samma vokabulär som `grade_status` i `GET /partner/plants`. De två endpointerna kan aldrig visa olika lägen för samma anläggning."},"period_start":{"type":"string","title":"Period Start","description":"Första dygnet Wolta har data för anläggningen. Beskriver täckningen, inte exakt det fönster senaste beräkningen räknade på."},"period_end":{"type":"string","title":"Period End","description":"Sista dygnet Wolta har data för anläggningen."},"grade_version":{"type":"string","title":"Grade Version","description":"Version av betygslogiken bakom siffran. Jämför inte betyg över en versionsändring rakt av.","examples":["7"]},"flex":{"anyOf":[{"$ref":"#/components/schemas/PartnerFlex"},{"type":"null"}],"description":"Extern styrning och reservation i betygsfönstret. Nyckeln UTELÄMNAS helt när fönstret saknar både extern styrning och reservation - den är aldrig null."}},"type":"object","required":["client_plant_id","status","period_start","period_end","grade_version"],"title":"GradeRow"},"GradesPage":{"properties":{"grades":{"items":{"$ref":"#/components/schemas/GradeRow"},"type":"array","title":"Grades"},"total":{"type":"integer","title":"Total","description":"Hela flottans storlek, inte antalet rader på sidan."}},"type":"object","required":["grades","total"],"title":"GradesPage"},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"InterestIn":{"properties":{"system":{"type":"string","maxLength":40,"title":"System"},"system_name":{"anyOf":[{"type":"string","maxLength":60},{"type":"null"}],"title":"System Name","description":"Systemets namn i fritext. Tas bara emot tillsammans med `system` = `annat`; med ett annat system ger fältet 422."},"email":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Email"}},"type":"object","required":["system"],"title":"InterestIn"},"LinkIn":{"properties":{"email":{"type":"string","maxLength":200,"title":"Email"},"profile_token":{"anyOf":[{"type":"string","minLength":1},{"type":"null"}],"title":"Profile Token","description":"Anläggningens ägar-token. Uteslut när claim_code anges."},"claim_code":{"anyOf":[{"type":"string","maxLength":64,"minLength":1},{"type":"null"}],"title":"Claim Code","description":"Kopplingskod från Home Assistant-integrationen. Skapar kontot och kopplar anläggningen vid bekräftelsen. Uteslut när profile_token anges."},"turnstile_token":{"type":"string","title":"Turnstile Token"}},"type":"object","required":["email","turnstile_token"],"title":"LinkIn"},"LinkRotated":{"properties":{"link_token":{"type":"string","title":"Link Token","description":"Den nya slutkundslänkens nyckel. Den gamla slutar fungera omedelbart.","examples":["wpl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]}},"type":"object","required":["link_token"],"title":"LinkRotated"},"LoginIn":{"properties":{"email":{"type":"string","maxLength":200,"title":"Email"},"turnstile_token":{"type":"string","title":"Turnstile Token"}},"type":"object","required":["email","turnstile_token"],"title":"LoginIn"},"PartnerFlex":{"properties":{"flagged_hours":{"type":"integer","title":"Flagged Hours","description":"Antal timrader NI flaggat med `external_control: true` i betygsfönstret. Räknar bara er egen flaggning - se `comparable` för domen, som även väger in reservation.","examples":[731]},"flagged_share":{"type":"number","title":"Flagged Share","description":"Andelen av betygsfönstrets rader NI flaggat, avrundad till fyra decimaler. Räknar bara er egen flaggning, inte reservation. Grinda aldrig på andelen ensam - den kan avrundas till 0 med ett `flagged_hours` över noll.","examples":[0.0834]},"foregone_value_sek":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Foregone Value Sek","description":"Uteblivet värde i kronor: skillnaden i anläggningens totala ekonomiska värde (inklusive nättariff och skatt, inte bara spotpriset) mellan ett fritt batteri och det som faktiskt kördes under BÅDE externt styrda och reserverade perioder, räknat över BETYGSFÖNSTRET - inte över `period_start`-`period_end`. Kan vara negativt: den faktiska styrningen kan råka ge ett högre värde än det fria fallet. Null när talet inte gick att räkna.","examples":[214.5]},"comparable":{"type":"boolean","title":"Comparable","description":"Falskt när anläggningen ligger utanför Woltas jämförelsegrupp för att en för stor del av tiden var externt styrd ELLER reserverad - unionen av de två. Betyget i `score` gäller fortfarande anläggningen själv - det är jämförelsen mot andra som inte håller.","examples":[true]}},"type":"object","required":["flagged_hours","flagged_share","comparable"],"title":"PartnerFlex"},"PartnerMeOut":{"properties":{"name":{"type":"string","title":"Name","description":"Partnerns namn.","examples":["Exempelbolaget AB"]},"slug":{"type":"string","title":"Slug","description":"Partnerns identifierare hos Wolta.","examples":["exempelbolaget-ab"]},"tier":{"type":"string","title":"Tier","description":"Nivån partnerskapet ligger på.","examples":["dev-free"]},"plant_count":{"type":"integer","title":"Plant Count","description":"Antal anläggningar ni har just nu.","examples":[3]},"plant_limit":{"type":"integer","title":"Plant Limit","description":"Högsta antal anläggningar er tier tillåter.","examples":[10]},"rate_max_per_min":{"type":"integer","title":"Rate Max Per Min","description":"Er rate-budget i anrop per minut.","examples":[120]}},"type":"object","required":["name","slug","tier","plant_count","plant_limit","rate_max_per_min"],"title":"PartnerMeOut"},"PlantCreate":{"properties":{"client_plant_id":{"type":"string","maxLength":128,"minLength":1,"pattern":"^(?!\\.{1,2}$)[^\\s/?#%\\\\]+$","title":"Client Plant Id","description":"Ert eget stabila id för anläggningen. Används som sökvägssegment i alla senare anrop och måste därför vara URL-säkert: inga mellanslag, snedstreck, ?, #, % eller backslash, och inte bara `.` eller `..`. Högst 128 tecken.","examples":["exb-001"]},"zone":{"type":"string","title":"Zone","description":"Elområde/priszon, t.ex. `SE3`. Trimmas och versaliseras före validering. Zonen är oföränderlig efter skapandet.","examples":["SE3"]},"control_system":{"type":"string","enum":["aikion","checkwatt","emaldo","emhass","ferroamp","greenely","huawei","keepai","manual","other","pixii","reduxi","self_consumption","sigenergy","sonnen","tibber"],"title":"Control System","description":"Styrsystemet som styr batteriet. Valideras strikt - passar inget av värdena använd `other`. Fältet är obligatoriskt eftersom betygen grupperas per styrsystem i jämförelsedatan.","examples":["other"]},"battery_kwh":{"type":"number","exclusiveMinimum":0,"title":"Battery Kwh","description":"Batteriets kapacitet i kWh.","examples":[10]},"battery_kw":{"type":"number","exclusiveMinimum":0,"title":"Battery Kw","description":"Batteriets effekt i kW.","examples":[5]},"eff":{"anyOf":[{"type":"number","maximum":1,"exclusiveMinimum":0},{"type":"null"}],"title":"Eff","description":"Verkningsgrad tur och retur. Utelämnad sätts 0,9.","examples":[0.9]},"nameplate_kwh":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Nameplate Kwh","description":"Märkkapacitet, om den skiljer sig från den levererbara kapaciteten (t.ex. vid degraderat batteri).","examples":[15]},"reserve_pct":{"anyOf":[{"type":"number","maximum":100,"minimum":0},{"type":"null"}],"title":"Reserve Pct","description":"Andel av batteriet i procent som reserveras och inte används för optimering.","examples":[10]}},"type":"object","required":["client_plant_id","zone","control_system","battery_kwh","battery_kw"],"title":"PlantCreate"},"PlantCreated":{"properties":{"client_plant_id":{"type":"string","title":"Client Plant Id","description":"Ert id för anläggningen.","examples":["exb-001"]},"link_token":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Link Token","description":"Slutkundslänkens nyckel. Sätts bara i 201-svaret vid det FÖRSTA skapandet - ett upprepat (idempotent) anrop ger `null`. Spara den direkt, den visas aldrig igen.","examples":["wpl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"]}},"type":"object","required":["client_plant_id","link_token"],"title":"PlantCreated"},"PlantPatched":{"properties":{"client_plant_id":{"type":"string","title":"Client Plant Id"},"zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zone"},"control_system":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Control System"},"battery_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kwh"},"battery_kw":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kw"},"eff":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eff"},"nameplate_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Nameplate Kwh"},"reserve_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Reserve Pct"}},"type":"object","required":["client_plant_id"],"title":"PlantPatched","description":"Svaret på PATCH: partnerägda fält, aldrig slutkundens ekonomi eller tariff."},"PlantRow":{"properties":{"client_plant_id":{"type":"string","title":"Client Plant Id"},"zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zone"},"control_system":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Control System"},"first_hour":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"First Hour","description":"Tidsstämpel för den första timme Wolta har data för. `null` innan anläggningen strömmat något."},"last_hour":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last Hour","description":"Tidsstämpel för den senaste timme Wolta har data för."},"n_days":{"type":"integer","title":"N Days","description":"Antal distinkta lokala dygn med data, räknat tidszonsmedvetet - alltså inte antal timmar delat med 24."},"grade_status":{"type":"string","enum":["none","collecting","check_data","below_baseline","ok"],"title":"Grade Status","description":"Betygsstatus: `none` (under 7 dygns data), `collecting` (7-29 dygn), `check_data` (30+ dygn men inget säkert betyg), `below_baseline` (giltigt men negativt netto) eller `ok`."}},"type":"object","required":["client_plant_id","n_days","grade_status"],"title":"PlantRow"},"PlantsPage":{"properties":{"plants":{"items":{"$ref":"#/components/schemas/PlantRow"},"type":"array","title":"Plants"},"total":{"type":"integer","title":"Total","description":"Hela flottans storlek, inte antalet rader på sidan."}},"type":"object","required":["plants","total"],"title":"PlantsPage"},"PrefIn":{"properties":{"kind":{"type":"string","title":"Kind"},"enabled":{"type":"boolean","title":"Enabled"},"submission_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Submission Id"}},"type":"object","required":["kind","enabled"],"title":"PrefIn"},"ProfileCreate":{"properties":{"zone":{"type":"string","title":"Zone"},"battery_kwh":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Battery Kwh"},"battery_kw":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Battery Kw"},"battery_declared":{"type":"boolean","title":"Battery Declared","description":"Anläggningen har ett batteri men kapacitet/effekt är okända: Wolta mäter dem ur driftdatan. Utelämna då `battery_kwh`/`battery_kw`.","default":false},"eff":{"type":"number","maximum":1,"exclusiveMinimum":0,"title":"Eff","default":0.9},"has_solar":{"type":"boolean","title":"Has Solar","default":false},"share_profile":{"type":"boolean","title":"Share Profile","default":false},"pv_kwp":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Pv Kwp"},"cost_sek":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"title":"Cost Sek"},"purchase_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"},"grid_var_ore":{"anyOf":[{"type":"number","maximum":500,"minimum":0},{"type":"null"}],"title":"Grid Var Ore"},"surcharge_ore":{"anyOf":[{"type":"number","maximum":500,"minimum":0},{"type":"null"}],"title":"Surcharge Ore"},"export_extra_ore":{"anyOf":[{"type":"number","maximum":500,"minimum":-200},{"type":"null"}],"title":"Export Extra Ore"},"grid_var_pct":{"anyOf":[{"type":"number","maximum":100,"minimum":0},{"type":"null"}],"title":"Grid Var Pct"},"export_extra_pct":{"anyOf":[{"type":"number","maximum":100,"minimum":-100},{"type":"null"}],"title":"Export Extra Pct"},"reserve_pct":{"anyOf":[{"type":"number","maximum":100,"minimum":0},{"type":"null"}],"title":"Reserve Pct"},"nameplate_kwh":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Nameplate Kwh"},"nameplate_kw":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Nameplate Kw"},"battery_events":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Battery Events"},"client_plant_id":{"anyOf":[{"type":"string","maxLength":200,"minLength":16},{"type":"null"}],"title":"Client Plant Id"},"control_system":{"anyOf":[{"type":"string","maxLength":50},{"type":"null"}],"title":"Control System","description":"Styrsystemet som styr batteriet. Valideras strikt – passar inget av värdena, använd `other` och ange namnet i `control_system_name`. Utelämnat vid om-onboarding behålls tidigare värde."},"control_system_name":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Control System Name","description":"Fritextnamn på styrsystemet när `control_system` är `other`."}},"type":"object","required":["zone"],"title":"ProfileCreate"},"ProfileIn":{"properties":{"profile_token":{"type":"string","title":"Profile Token"}},"type":"object","required":["profile_token"],"title":"ProfileIn"},"ProfilePatch":{"properties":{"cost_sek":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Cost Sek"},"purchase_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"},"paid_solar_sek":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Paid Solar Sek"},"purchase_date_solar":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date Solar"},"battery_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kwh"},"battery_kw":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Kw"},"eff":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Eff"},"pv_kwp":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Pv Kwp"},"zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zone"},"grid_var_ore":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Grid Var Ore"},"surcharge_ore":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Surcharge Ore"},"export_extra_ore":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Export Extra Ore"},"grid_var_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Grid Var Pct"},"export_extra_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Export Extra Pct"},"reserve_pct":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Reserve Pct"},"nameplate_kwh":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Nameplate Kwh"},"nameplate_kw":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Nameplate Kw"},"battery_events":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Battery Events"},"solar_events":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Solar Events"},"grade_start_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Grade Start Date"},"grade_window_days":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Grade Window Days"},"control_system":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Control System"},"control_system_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Control System Name"},"label":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Label"},"battery_life_years":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Battery Life Years"},"max_cycles":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Cycles"},"solar_degradation":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Solar Degradation"},"battery_degradation":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Battery Degradation"},"flex_compensation":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Flex Compensation"},"flex_aggregator":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flex Aggregator"},"flex_bid_kw":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Flex Bid Kw"},"flex_reservation":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Flex Reservation"},"flex_reserved_from":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Flex Reserved From"},"flex_reservations":{"anyOf":[{"items":{"additionalProperties":true,"type":"object"},"type":"array"},{"type":"null"}],"title":"Flex Reservations"}},"type":"object","title":"ProfilePatch","description":"Alla fält valfria – bara de angivna uppdateras. cost_sek/purchase_date = ekonomi (billig\nUPDATE); battery_*/eff/pv_kwp = anläggning (kräver omräkning av betyget). zone får rättas\ninom samma valuta, ett byte över valutagränsen ger 422, och samma värde som redan är\nlagrat är ett no-op."},"QuarantineField":{"properties":{"field":{"type":"string","enum":["solar_kwh","grid_import_kwh","grid_export_kwh","batt_charged_kwh","batt_discharged_kwh"],"title":"Field","description":"Fältet som bröt mot regeln."},"value":{"type":"number","title":"Value","description":"Fältets summa för klocktimmen, kWh."},"cap":{"type":"number","title":"Cap","description":"Taket fältet bröt mot, kWh för klocktimmen."},"layer":{"type":"string","enum":["A","B","C","D"],"title":"Layer","description":"Regelns lager som fällde timmen."},"evidence":{"anyOf":[{"type":"string","enum":["soc_refuted","unsupported","none"]},{"type":"null"}],"title":"Evidence","description":"Bara på lager C: varför värdet inte bekräftades av andra mätningar."}},"type":"object","required":["field","value","cap","layer","evidence"],"title":"QuarantineField"},"QuarantineHour":{"properties":{"hour_utc":{"type":"string","title":"Hour Utc","description":"Klocktimmens start i UTC (ISO 8601)."},"fields":{"items":{"$ref":"#/components/schemas/QuarantineField"},"type":"array","title":"Fields","description":"Fälten som bröt, i fast ordning: sol, nätimport, nätexport, laddat, urladdat."}},"type":"object","required":["hour_utc","fields"],"title":"QuarantineHour"},"QuarantineOut":{"properties":{"systematic":{"type":"boolean","title":"Systematic","description":"Sant när felet ser systematiskt ut; listan är då tom."},"total_hours":{"type":"integer","title":"Total Hours","description":"Antal timmar i listan."},"tz":{"type":"string","title":"Tz","description":"Anläggningens tidszon (IANA), för lokal tid."},"hours":{"items":{"$ref":"#/components/schemas/QuarantineHour"},"type":"array","title":"Hours","description":"Timmarna, nyast först."}},"type":"object","required":["systematic","total_hours","tz","hours"],"title":"QuarantineOut"},"ShareCreate":{"properties":{"profile_token":{"type":"string","title":"Profile Token"},"wear_on":{"type":"boolean","title":"Wear On","default":true}},"type":"object","required":["profile_token"],"title":"ShareCreate"},"ShareIn":{"properties":{"wear_on":{"type":"boolean","title":"Wear On","default":true}},"type":"object","title":"ShareIn"},"SimulateIn":{"properties":{"mode":{"type":"string","title":"Mode","default":"decision"},"pv_kwp":{"type":"number","maximum":500,"exclusiveMinimum":0,"title":"Pv Kwp","default":10},"load_annual":{"type":"number","maximum":200000,"exclusiveMinimum":0,"title":"Load Annual","default":20000},"has_battery":{"type":"boolean","title":"Has Battery","default":true},"kwh":{"type":"number","maximum":10000,"exclusiveMinimum":0,"title":"Kwh","default":10},"kw":{"type":"number","maximum":10000,"exclusiveMinimum":0,"title":"Kw","default":5},"eff":{"type":"number","maximum":1,"exclusiveMinimum":0.3,"title":"Eff","default":0.9},"realism_factor":{"anyOf":[{"type":"number","maximum":1,"exclusiveMinimum":0},{"type":"null"}],"title":"Realism Factor"},"selfuse_capture":{"anyOf":[{"type":"number","maximum":1,"exclusiveMinimum":0},{"type":"null"}],"title":"Selfuse Capture"},"solar_export_capture":{"anyOf":[{"type":"number","maximum":1,"exclusiveMinimum":0},{"type":"null"}],"title":"Solar Export Capture"},"capex_battery":{"type":"number","minimum":0,"title":"Capex Battery","default":0},"capex_solar":{"type":"number","minimum":0,"title":"Capex Solar","default":0},"persons":{"type":"integer","maximum":10,"minimum":1,"title":"Persons","default":1},"green_mode":{"type":"string","title":"Green Mode","default":"off"},"green_manual":{"type":"number","minimum":0,"title":"Green Manual","default":0},"lifetime_years":{"type":"integer","maximum":40,"minimum":5,"title":"Lifetime Years","default":30},"battery_life_years":{"anyOf":[{"type":"integer","maximum":40,"minimum":1},{"type":"null"}],"title":"Battery Life Years"},"max_cycles":{"anyOf":[{"type":"integer","maximum":15000,"minimum":2000},{"type":"null"}],"title":"Max Cycles"},"house_type":{"type":"string","title":"House Type","default":"heated"},"battery_degradation":{"anyOf":[{"type":"number","maximum":0.2,"minimum":0},{"type":"null"}],"title":"Battery Degradation"},"solar_degradation":{"anyOf":[{"type":"number","maximum":0.2,"minimum":0},{"type":"null"}],"title":"Solar Degradation"},"inverter_replace":{"type":"boolean","title":"Inverter Replace","default":false},"inverter_replace_year":{"type":"integer","maximum":40,"minimum":1,"title":"Inverter Replace Year","default":15},"inverter_replace_cost":{"type":"number","minimum":0,"title":"Inverter Replace Cost","default":20000},"future_price_factor":{"type":"number","maximum":3,"exclusiveMinimum":0,"title":"Future Price Factor","default":1},"battery_only_economics":{"type":"boolean","title":"Battery Only Economics","default":false},"purchase_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"},"paid":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Paid"},"purchase_date_solar":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date Solar"},"purchase_date_battery":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date Battery"},"paid_solar":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"title":"Paid Solar"},"paid_battery":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"title":"Paid Battery"},"pv_orient":{"anyOf":[{"type":"string","maxLength":40},{"type":"null"}],"title":"Pv Orient"}},"type":"object","title":"SimulateIn","description":"Parametrar för hushållsekonomin. Zonen hämtas alltid från anläggningen, inte från kroppen."},"SizingIn":{"properties":{"mode":{"type":"string","title":"Mode","default":"capacity"},"kr_per_kwh":{"type":"number","exclusiveMinimum":0,"title":"Kr Per Kwh","default":7000},"expansion_kr_per_kwh":{"type":"number","exclusiveMinimum":0,"title":"Expansion Kr Per Kwh","default":3500},"max_cycles":{"anyOf":[{"type":"number","maximum":15000,"minimum":2000},{"type":"null"}],"title":"Max Cycles"},"calendar_years":{"anyOf":[{"type":"integer","maximum":40,"minimum":1},{"type":"null"}],"title":"Calendar Years"},"battery_degradation":{"anyOf":[{"type":"number","maximum":0.2,"minimum":0},{"type":"null"}],"title":"Battery Degradation"},"kw_per_kwh":{"type":"number","exclusiveMinimum":0,"title":"Kw Per Kwh","default":0.5},"green_mode":{"type":"string","title":"Green Mode","default":"off"},"persons":{"type":"integer","maximum":10,"minimum":1,"title":"Persons","default":1},"realistic":{"type":"boolean","title":"Realistic","default":true},"cabinet_kwh":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Cabinet Kwh"},"cabinet_cost":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Cabinet Cost"},"inverter_cost":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Inverter Cost"},"capture":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Capture"}},"type":"object","title":"SizingIn","description":"Parametrar för dimensioneringsberäkningen. Zon och batteri hämtas alltid från anläggningen, inte från kroppen."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"elpris_api__api__reduxi_onboard__OnboardRequest":{"properties":{"unit_id":{"type":"string","maxLength":64,"minLength":3,"title":"Unit Id"},"zone":{"type":"string","title":"Zone"},"battery_kwh":{"type":"number","exclusiveMinimum":0,"title":"Battery Kwh"},"battery_kw":{"type":"number","exclusiveMinimum":0,"title":"Battery Kw"},"has_solar":{"type":"boolean","title":"Has Solar","default":false},"pv_kwp":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Pv Kwp"},"cost_sek":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"title":"Cost Sek"},"purchase_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"}},"type":"object","required":["unit_id","zone","battery_kwh","battery_kw"],"title":"OnboardRequest"},"elpris_api__api__sonnen__OnboardRequest":{"properties":{"zone":{"type":"string","title":"Zone"},"battery_kwh":{"type":"number","exclusiveMinimum":0,"title":"Battery Kwh"},"battery_kw":{"type":"number","exclusiveMinimum":0,"title":"Battery Kw"},"has_solar":{"type":"boolean","title":"Has Solar","default":false},"pv_kwp":{"anyOf":[{"type":"number","exclusiveMinimum":0},{"type":"null"}],"title":"Pv Kwp"},"cost_sek":{"anyOf":[{"type":"number","minimum":0},{"type":"null"}],"title":"Cost Sek"},"purchase_date":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Purchase Date"}},"type":"object","required":["zone","battery_kwh","battery_kw"],"title":"OnboardRequest"}},"securitySchemes":{"ProfileToken":{"type":"http","description":"Anläggningens profil-token: `Authorization: Bearer <profile_token>`","scheme":"bearer"},"PartnerKey":{"type":"http","description":"Partner-API-nyckel: `Authorization: Bearer wpk_...`","scheme":"bearer"},"Session":{"type":"apiKey","description":"Sessionskaka som sätts av inloggningen (POST /account/confirm). Webbens egen transport - sätts och skickas av webbläsaren.","in":"cookie","name":"__Host-wolta_session"}}},"tags":[{"name":"priser","description":"Spotpriser, historik, jämförelser och stödtjänstmarknader. Öppna GET-endpoints utan nyckel. Prissvaren bär ett `source`-fält med attribution: rådatan kommer från Svenska kraftnät, elprisetjustnu.se och ENTSO-E."},{"name":"betyg","description":"Optimeringsbetyget: ladda upp batteridrift, följ den köade beräkningen och läs jämförelsedatan bakom betyget. Tunga beräkningar köas och pollas, de svarar aldrig synkront."},{"name":"anläggning","description":"En sparad anläggning: parametrar, löpande driftdata, omräkning, resultat och dimensionering. Autentiseras med anläggningens profil-token som `Authorization: Bearer`.","externalDocs":{"description":"Så fungerar betyget","url":"https://wolta.se/om"}},{"name":"konto","description":"Inloggning med e-postlänk, sessioner och kopplade anläggningar. Webbens egen transport: autentiseras med sessionskaka, inte token."},{"name":"integrationer","description":"Anslutningar som strömmar driftdata automatiskt: Sonnen, Reduxi och direktkopplingar till tillverkarnas molntjänster."},{"name":"partner","description":"Partner-API för den som kopplar in en hel flotta batterianläggningar: skapa anläggningar, mata in timdata löpande och läs tillbaka optimeringsbetyg. Egen nyckel (`wpk_`), egen rate-budget och en hård gräns på antal anläggningar. Registrering och nyckel via wolta.se/partner/portal.","externalDocs":{"description":"Kom igång med partner-API:t","url":"https://wolta.se/partner/docs"}},{"name":"delning","description":"Delbara betygslänkar och deras förhandsbilder."},{"name":"drift","description":"Hälsokontroll för övervakning."}],"externalDocs":{"description":"API-översikt på wolta.se","url":"https://wolta.se/api"}}