{"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 och får användas fritt även kommersiellt, med attribution. Woltas egna beräkningar (optimeringsbetyg, lönsamhetskalkyl, dimensionering) kräver avtal för kommersiell användning: kontakt@wolta.se. Villkor: https://wolta.se/villkor","termsOfService":"https://wolta.se/villkor","contact":{"name":"Wolta","url":"https://wolta.se/api","email":"kontakt@wolta.se"},"version":"0.80.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-09, kvartsvärden efter.\n- `resolution=1h` ger timmedel, `1d`/`1mo` aggregat per kalenderdygn respektive månad.\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.","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/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.","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, ENTSO-E eller interpolerad) 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.","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/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.","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`, `battery_kwh` och `battery_kw` (båda > 0, vägen kräver batteri). 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.\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.","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. Batteriflöden rimlighetsprövas dessutom per klocktimme mot redan lagrat tillstånd: överstiger timmens laddning eller urladdning batteriets effekt med marginal (×1,5) nollställs timmens batterifält i stället för att batchen nekas, och `repaired_battery_rows` i svaret räknar dem. En korrigerad omsändning skriver in riktiga värden igen.\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**).","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å.","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. Nya klienter bör använda headervarianten.","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.","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/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/import/solaredge":{"post":{"tags":["integrationer"],"summary":"Importera från SolarEdge","description":"Hämtar historisk produktion och batteridata från SolarEdges monitoringsplattform med en API-nyckel som ägaren själv tagit fram, och lägger in den som driftdata. Körs som ett jobb: svaret bär `job_id` som pollas via statusendpointen nedan. Elområde är obligatoriskt när profilen skapas (steg 2, med `site_id` satt) – saknas det svarar anropet 422 i stället för att anta ett värde.","operationId":"import_solaredge_api_v1_import_solaredge_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportRequest"}}},"required":true},"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"additionalProperties":true,"type":"object","title":"Response Import Solaredge Api V1 Import Solaredge 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/import/{job_id}/status":{"get":{"tags":["integrationer"],"summary":"Status för importjobb","description":"Följer ett pågående SolarEdge-jobb: hur långt det kommit och om det gått fel. Kräver jobbets token. Okänt jobb ger 404.","operationId":"import_status_api_v1_import__job_id__status_get","parameters":[{"name":"job_id","in":"path","required":true,"schema":{"type":"integer","title":"Job Id"}},{"name":"token","in":"query","required":true,"schema":{"type":"string","title":"Token"}}],"responses":{"200":{"description":"Lyckat svar.","content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Response Import Status Api V1 Import  Job Id  Status 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/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.","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. Ö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":true,"title":"Body"}}}},"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\nInsättningen är en upsert per anläggning och timme, så att skicka om samma fönster är riskfritt. 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. `repaired_battery_rows` räknar timmar vars batteriflöden nollställts för att de bröt mot fysikaliska gränser; 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 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"}},"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/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/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. Svarar alltid **202** oavsett om adressen redan finns, så att svaret inte avslöjar 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":"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"}}}},"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/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"}}}},"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. 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.","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}/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}/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"},"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","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"},"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":"auto"},"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"},"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 lagrade timrader vars batteriflöden nollställts för att de bröt mot fysikaliska gränser. Över 0 tyder på felaktig sensorkonfiguration eller ett hopp i er data.","examples":[0]}},"type":"object","required":["inserted_hours","first","last","repaired_battery_rows"],"title":"DataAppendResult"},"DataPut":{"properties":{"rows":{"items":{"$ref":"#/components/schemas/DataRow"},"type":"array","maxItems":40000,"minItems":1,"title":"Rows"}},"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}},"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":["3"]}},"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"},"ImportRequest":{"properties":{"zone":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Zone"},"battery_kwh":{"type":"number","exclusiveMinimum":0,"title":"Battery Kwh","default":1},"battery_kw":{"type":"number","exclusiveMinimum":0,"title":"Battery Kw","default":1},"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`."},"api_key":{"type":"string","maxLength":200,"minLength":1,"title":"Api Key"},"site_id":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Site Id"}},"type":"object","required":["api_key"],"title":"ImportRequest"},"InterestIn":{"properties":{"system":{"type":"string","maxLength":40,"title":"System"},"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":{"type":"string","title":"Profile Token"},"turnstile_token":{"type":"string","title":"Turnstile Token"}},"type":"object","required":["email","profile_token","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"},"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. 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","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 betyg grupperas och viktas per styrsystem.","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":{"type":"number","exclusiveMinimum":0,"title":"Battery Kwh"},"battery_kw":{"type":"number","exclusiveMinimum":0,"title":"Battery Kw"},"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","battery_kwh","battery_kw"],"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"},"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"}},"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 är ett\nundantag bland anläggningsfälten: den är OFÖRÄNDERLIG efter skapande – samma värde som\nredan är lagrat tolereras som no-op (partner-klienter ekar hela objekt), varje ÄNDRING\nger 422. Se patch_profile_core."},"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":"auto"},"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 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 import från SolarEdge."},{"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"}}