Kom igång med Woltas partner-API
Den här guiden beskriver hur en partner kopplar in sin flotta av batterianläggningar
mot Wolta via /api/v1/partner/: skapar anläggningar, matar in timdata löpande och
läser tillbaka optimeringsbetyg.
Optimeringsbetyget är Woltas mått på hur väl en anläggnings styrning presterar jämfört med ett passivt batteri, efter slitage, ställt mot vad andra anläggningar i Woltas jämförelsedata åstadkommer. Skalan går från 0 till 105. Avsnitt 4 beskriver hur ni läser betyget och vad de olika statusarna betyder.
API:t är fristående från Woltas publika API, som privatpersoner använder för att ladda upp en enskild anläggning. Partner-API:t har egen autentisering, egen rate-budget och en hård gräns på hur många anläggningar ni får ha. Både gränsen och budgeten följer av er tier, alltså den nivå partnerskapet ligger på.
Innehåll
- Nyckel och autentisering
- Skapa anläggningar
- Backfill och löpande datamatning
- Läsa betyg
- Slutkundslänkar
- Felkoder
- Portalen
- Support och ändringar
Maskinläsbar specifikation. Hela API-ytan finns som OpenAPI på wolta.se/api/v1/openapi.json, med scheman, felkoder och exempel per endpoint. Den går att generera klienter ur och läsa som interaktiv referens i Scalar. Den här guiden beskriver flödet och avvägningarna; specen beskriver fälten.
Engelsk version av samma spec: openapi.en.json och Scalar (engelska). Samma kontrakt, samma versionsnummer, bara översatta texter.
1. Nyckel och autentisering
Nyckel via självregistrering. Gå till wolta.se/partner/portal och ange er e-postadress. Wolta skickar en länk till adressen. Har ni inget Wolta-konto sedan tidigare skapas ett automatiskt. Ni behöver ingen egen anläggning för att bli partner. Klicka på länken i mejlet: den loggar er in och tar er direkt till portalen. Länken gäller en kort stund och kan bara användas en gång.
Väl inne anger ni företagsnamnet (minst två tecken; en kort beskrivning av användningsfallet är frivillig) och får direkt en API-nyckel på dev-free-tiern:
| dev-free | |
|---|---|
| Anläggningar | 10 |
| Rate-budget | 120 anrop/minut |
| Kostnad | gratis |
| Avsedd för | test och utveckling |
Nyckeln (format wpk_...) visas i klartext en gång, i svaret på registreringen.
Wolta lagrar den bara hashad och kan aldrig visa den igen. Tappar ni bort den roterar
ni fram en ny i portalen (avsnitt 7). Den gamla slutar då fungera omedelbart.
Varje konto kan bara vara kopplat till en partner. Ett andra registreringsförsök på samma konto ger 409.
Kommersiell drift kräver en tier-uppgradering: fler anläggningar och högre rate-budget. Kontakta Wolta (avsnitt 8).
Bas-URL: https://wolta.se/api/v1/partner/
Autentisering: varje anrop till /api/v1/partner/... måste ha headern
Authorization: Bearer wpk_din-nyckel-här
Ett bra första anrop för att verifiera att nyckeln fungerar och se er status:
curl -s https://wolta.se/api/v1/partner/me \
-H "Authorization: Bearer wpk_din-nyckel-här"
Svar:
{
"name": "Exempelbolaget AB",
"slug": "exempelbolaget-ab",
"tier": "dev-free",
"plant_count": 3,
"plant_limit": 10,
"rate_max_per_min": 120
}
plant_limit och rate_max_per_min är era faktiska, aktuella värden. Läs dem härifrån
i stället för att hårdkoda tier-siffror i er integration, eftersom de ändras när ni
uppgraderar.
Rate-budget. Varje partner har en egen budget, skild från Woltas publika API.
Er trafik konkurrerar aldrig med vanliga besökares. Budgeten fungerar som en hink
med rate_max_per_min platser (120 per minut på dev-free; läs ert aktuella värde
från /partner/me ovan). Hinken fylls på kontinuerligt i samma takt, så ni kan
antingen bränna hela hinken i en enda rusning eller sprida anropen jämnt över
minuten.
Går budgeten över svarar API:t med 429 och headern Retry-After: 30 (sekunder).
Vänta den tiden och försök igen. Ett 429 betyder inte att något gick fel med
föregående anrop, bara att hinken just nu är tom. Sprid ut anropen över tid, till
exempel en batch i taget per anläggning, i stället för att göra allt på en gång.
Retry-After: 30 gäller er egen partner-budget. Bakom den ligger ett yttre,
IP-baserat DoS-skydd som delas av alla partner-klienter bakom samma NAT eller IP.
En välskött integration bör mycket sällan trigga det, men om det ändå händer svarar
skyddet med Retry-After: 60. Läs alltid headern och vänta den tid den anger, i
stället för att anta att den alltid är 30.
Hela API-ytan
API:t har åtta endpoints. Alla ligger under bas-URL:en ovan och tar samma
Authorization-header:
| Metod och väg | Gör | Avsnitt |
|---|---|---|
GET /partner/me |
Er status: namn, tier, antal anläggningar, gränser | 1 |
POST /partner/plants |
Skapa (eller idempotent återfinna) en anläggning | 2 |
GET /partner/plants |
Lista flottan med datatäckning och betygsstatus | 3 |
PATCH /partner/plants/{client_plant_id} |
Ändra tekniska fält på en anläggning | 2 |
DELETE /partner/plants/{client_plant_id} |
Radera en anläggning | 2 |
POST /partner/plants/{client_plant_id}/data |
Skicka timdata (backfill och löpande) | 3 |
POST /partner/plants/{client_plant_id}/link/rotate |
Rotera anläggningens slutkundslänk | 5 |
GET /partner/grades |
Läsa senaste betyg för hela flottan | 4 |
Det finns ingen endpoint för att läsa en enskild anläggning. Behöver ni en
anläggnings tillstånd hämtar ni GET /partner/plants eller GET /partner/grades
och filtrerar på client_plant_id. Båda är paginerade och tänkta att läsas i batch.
En normal integration går i den här ordningen: POST /partner/plants en gång per
anläggning → spara link_token → backfilla historik med POST .../data → synka nya
timmar löpande → polla GET /partner/grades en gång per dygn.
2. Skapa anläggningar
POST /partner/plants skapar en anläggning i Wolta som motsvarar en av era
batterianläggningar.
Fält
| Fält | Typ | Krav | Beskrivning |
|---|---|---|---|
client_plant_id |
sträng | obligatoriskt, 1–128 tecken | Ert eget stabila ID för anläggningen. Wolta använder det för att identifiera anläggningen i alla senare anrop (data, PATCH, DELETE, länk-rotation). Det är alltså er nyckel, inte Woltas interna ID. Måste vara URL-säkert: det används som ett segment i sökvägen till övriga anrop, så mellanslag, /, ?, #, % och backslash ger 422. Övriga tecken går bra. |
zone |
sträng | obligatoriskt | Elområde/priszon anläggningen ligger i, t.ex. SE3. Normaliseras (trimmas och versaliseras) innan validering. Zoner som Wolta inte har stöd för ger 422 "zonen stöds inte ännu". |
control_system |
sträng | obligatoriskt | Styrsystemet som styr batteriet. Måste vara ett av de giltiga värdena nedan. Valideras strikt, ingen tyst fallback till “okänt” – ogiltigt värde ger 422 "okänt styrsystem". |
battery_kwh |
tal | obligatoriskt, > 0 | Batteriets kapacitet i kWh. Fältet har ingen default – utelämnas det ger anropet 422. |
battery_kw |
tal | obligatoriskt, > 0 | Batteriets effekt i kW. Fältet har ingen default – utelämnas det ger anropet 422. |
eff |
tal | valfritt, > 0 och ≤ 1 | Verkningsgrad (round-trip). Måste vara strikt större än 0 (eff: 0 ger 422). Utelämnas fältet sätter Wolta 0,9 som default. |
nameplate_kwh |
tal | valfritt, > 0 | Märkkapacitet om den skiljer sig från battery_kwh (t.ex. vid degraderat batteri). |
reserve_pct |
tal | valfritt, 0–100 | Reserverad batterikapacitet i procent som inte används för optimering. |
Giltiga värden för control_system:
emhass, sonnen, self_consumption, manual, reduxi, other,
tibber, checkwatt, greenely, aikion, sigenergy, emaldo, ferroamp, huawei, pixii
Passar inget av värdena in på er anläggning använder ni other. Fältet är
obligatoriskt eftersom Wolta grupperar och viktar betyg per styrsystem. Utan ett
korrekt värde hamnar anläggningen fel i den analysen.
Exempel
curl -s -X POST https://wolta.se/api/v1/partner/plants \
-H "Authorization: Bearer wpk_din-nyckel-här" \
-H "Content-Type: application/json" \
-d '{
"client_plant_id": "exb-001",
"zone": "SE3",
"control_system": "other",
"battery_kwh": 10.0,
"battery_kw": 5.0
}'
Svar vid första anropet (HTTP 201):
{
"client_plant_id": "exb-001",
"link_token": "wpl_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
Spara link_token direkt. Den visas bara i det här svaret. Av den bygger ni
slutkundslänken: den personliga adress ni ger anläggningens ägare för att ägaren ska
kunna se sitt betyg i Wolta. Avsnitt 5 går igenom vad ägaren kan göra där.
Idempotens
Anropet är idempotent på (er partner-identitet, client_plant_id). Skickar ni
samma client_plant_id igen (t.ex. för att er integration kör om ett
skapande-anrop efter timeout) returnerar Wolta 200 med samma client_plant_id och
link_token: null. Token visas alltså inte igen vid ett upprepat anrop. Det är
säkert att anropa POST /partner/plants flera gånger för samma anläggning.
Ändrad body vid upprepat anrop ignoreras tyst. Idempotensen slår bara på
client_plant_id; skickar ni samma client_plant_id men med t.ex. en annan
battery_kwh i ett senare anrop uppdateras ingenting: den befintliga raden
lämnas orörd och 200-svaret ser likadant ut som vid en oförändrad upprepning.
Vill ni ändra en anläggnings tekniska fält efter att den skapats, använd
PATCH (nedan), inte ett nytt POST med annan body.
Idempotenskollen ligger före tier-kollen: ett upprepat anrop för en anläggning ni redan har går igenom även när kvoten är full.
Tier-gräns
Varje partner har en hård gräns på antal anläggningar (plant_limit, 10 på
dev-free). Är gränsen nådd svarar Wolta med 409:
{
"detail": {
"error": "plant_limit_reached",
"plant_limit": 10
}
}
Så ser felsvaren ut. Alla felsvar i den här guiden ligger under nyckeln
detail. Läs alltså error som r.json()["detail"]["error"] i er klientkod, inte
som r.json()["error"].
Radera en anläggning ni inte längre behöver (se nedan) för att frigöra en plats, eller kontakta Wolta för att höja gränsen (avsnitt 8).
Uppdatera och radera anläggningar
PATCH /partner/plants/{client_plant_id} uppdaterar de tekniska fälten
(zone, control_system, battery_kwh, battery_kw, eff, nameplate_kwh,
reserve_pct), med ett undantag: zone accepteras i kroppen men kan bara
sättas till samma värde den redan har (se nedan). Alla andra fält (t.ex. ekonomi,
elavtal) ägs av slutkunden via länken (avsnitt 5) eller av den inloggade ägaren,
och kan inte sättas via partner-API:t. Ett sådant fält i kroppen ger 403 (se
felkodstabellen).
De numeriska gränserna är desamma som vid skapande: battery_kwh > 0,
battery_kw > 0, 0 < eff ≤ 1, nameplate_kwh > 0, reserve_pct 0–100.
Ett värde utanför gränsen ger 422.
Bara de fält ni faktiskt skickar ändras. Utelämnade fält lämnas orörda.
Skicka aldrig null. Ett explicit null på något av battery_kwh,
battery_kw, eff, nameplate_kwh, reserve_pct eller control_system ger
422, inte en nollställning:
{
"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"
}
}
Utelämna fältet i stället om ni inte vill ändra det.
Zon är oföränderlig efter skapande. zone/prisområde sätts en gång vid
POST /partner/plants och kan inte ändras via PATCH i efterhand. Zonen
styr valuta, skatt, tariff och tidszon för hela betygsberäkningen, och att flytta
en anläggning med redan lagrad timdata till en annan zon i efterhand skulle
tyst omtolka historiken som om den alltid legat i den nya zonens marknad.
Ett PATCH-anrop som skickar en zone som skiljer sig från den redan lagrade
ger 422:
{"detail": "zon kan inte ändras efter skapande - radera och skapa om anläggningen"}
Skickar ni zone med samma värde som redan är lagrat är det ett no-op (inget
fel, ingen omräkning triggas), praktiskt för integrationer som alltid postar hela
sitt lokalt cachade objekt vid PATCH. Har ni skrivit fel zon vid skapandet: radera
anläggningen (DELETE, nedan) och skapa om den med rätt zon (ny anläggning,
ny historik från start under rätt marknad), i stället för att flytta den
befintliga.
curl -s -X PATCH https://wolta.se/api/v1/partner/plants/exb-001 \
-H "Authorization: Bearer wpk_din-nyckel-här" \
-H "Content-Type: application/json" \
-d '{"battery_kwh": 15.0}'
Svaret (HTTP 200) innehåller client_plant_id plus de partnerägda fälten efter
uppdateringen, aldrig slutkundens ekonomi- eller tariffvärden:
{
"client_plant_id": "exb-001",
"zone": "SE3",
"control_system": "other",
"battery_kwh": 15.0,
"battery_kw": 5.0,
"eff": 0.9,
"nameplate_kwh": null,
"reserve_pct": null
}
DELETE /partner/plants/{client_plant_id} avvecklar en anläggning: bindningen,
timdatan och betygsraderna raderas enligt Woltas vanliga raderingsflöde, och en
plats i tier-gränsen frigörs. Radering sker en anläggning i taget. API:t har ingen
massradering av hela flottan, som skydd mot att en bugg i er integration råkar sopa
bort all data.
curl -s -X DELETE https://wolta.se/api/v1/partner/plants/exb-001 \
-H "Authorization: Bearer wpk_din-nyckel-här"
Svar: HTTP 204 (tom kropp).
3. Backfill och löpande datamatning
POST /partner/plants/{client_plant_id}/data skickar in timdata för en
anläggning. Samma endpoint används både för historisk backfill (skicka ett stort
fönster på en gång) och löpande synk (skicka nya timmar allt eftersom de blir
klara).
Format
curl -s -X POST https://wolta.se/api/v1/partner/plants/exb-001/data \
-H "Authorization: Bearer wpk_din-nyckel-här" \
-H "Content-Type: application/json" \
-d '{
"rows": [
{
"ts_utc": "2026-08-01T00:00:00Z",
"solar_kwh": 0.5,
"grid_import_kwh": 1.0,
"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.0,
"batt_charged_kwh": 0.1,
"batt_discharged_kwh": 0.3
}
]
}'
Kroppen måste vara ett JSON-objekt med nyckeln rows, och rows måste
innehålla minst en rad. En tom lista, en naken array eller trasig JSON ger 422.
Fälten per rad:
| Fält | Enhet | Krav |
|---|---|---|
ts_utc |
ISO 8601-tidsstämpel | Måste bära tidszon (antingen Z eller ett explicit offset, t.ex. +02:00). En naiv tidsstämpel utan tidszon (2026-08-01T00:00:00) ger 422. Wolta gissar aldrig lokaltid. |
solar_kwh |
kWh under timmen | valfritt, default 0, 0–500 |
grid_import_kwh |
kWh under timmen | valfritt, default 0, 0–500 |
grid_export_kwh |
kWh under timmen | valfritt, default 0, 0–500 |
batt_charged_kwh |
kWh under timmen | valfritt, default 0, 0–500 |
batt_discharged_kwh |
kWh under timmen | valfritt, default 0, 0–500 |
Övre gräns 500 kWh/timme per energifält. Ett värde över det ger 422. Gränsen ligger gott över vad en enskild timme rimligen kan innehålla, även för stora anläggningar. Den vanligaste orsaken till att träffa den är att värdet råkat skickas i Wh i stället för kWh (t.ex. 500 000 i stället för 500). Dela med 1000 om ni ser 422 på ett energifält här.
Det finns ingen egen last-kolumn. Wolta härleder hushållets/anläggningens förbrukning ur import, sol och batteriflöden, precis som för övriga integrationskällor (Sonnen, Reduxi m.fl.).
Svar:
{
"inserted_hours": 2,
"first": "2026-08-01T00:00:00+00:00",
"last": "2026-08-01T01:00:00+00:00",
"repaired_battery_rows": 0
}
inserted_hours/first/last beskriver enbart detta anrops batch (antal rader ni
skickade i just detta anrop, samt den batchens första/sista tidsstämpel), inte
anläggningens hela historik. Jämför med first_hour/last_hour/n_days i
GET /partner/plants nedan, som visar all data anläggningen någonsin fått inlagrad.
repaired_battery_rows är antalet batterirader som Wolta nollställde för att de
bröt mot fysikaliska gränser. Oftast är värdet 0. Ett värde större än 0 tyder på
felaktig sensorkonfiguration eller ett hopp i er data, till exempel en kumulativ
mätare som nollställts eller bytts ut. Se “Batterigränser” nedan.
Upsert-semantik
Insättning är per (anläggning, timme). Skickar ni samma timme igen skrivs den över. Anropet är idempotent. Det gör backfill enkelt: kör om samma fönster om ni är osäkra på om det redan skickats, ingen risk för dubbelräkning.
Storlekstak
Max 5 000 rader per anrop. Fler rader ger 413. Dela upp i flera batchar. 5 000 rader motsvarar ungefär 208 dygns timdata (~7 månader), vilket räcker med god marginal för en normal backfill-batch. Taket är även bytebaserat (2 MiB rå kroppsstorlek) och slår innan kroppen ens tolkas. En ovanligt pratig batch kan träffa bytetaket innan radtaket; dela upp stora batchar även då.
Det finns också ett totalt lagringstak per anläggning på 80 000 rader. Ett
anrop som skulle ta anläggningen förbi det ger 413 med
"profilen har nått maxstorlek (80000 rader) – radera och skapa ny". Vid timdata
motsvarar det drygt nio år och nås normalt aldrig av en partner-integration.
Hur ofta ni bör skicka data
Timvis eller glesare räcker gott. Betyg räknas inte per push. Wolta kör om betygen batchat när nya priser landat: efter dagens day-ahead-publicering (jobbet startar 13:15 svensk tid) och efter ENTSO-E-synken för utländska zoner (14:10). Nattjobbet 02:30 kör också om betygen när det ändrat prisunderlaget. Att pusha oftare än så ger inget snabbare betyg, bara mer trafik.
Wolta räknar dessutom om anläggningens årsprofil högst en gång per dygn. Årsprofilen är er inskickade timdata uppräknad till ett helår, både förbrukning och solproduktion, och den är det underlag modellen jämför den verkliga styrningen mot när betyget räknas. Dygnstaket börjar gälla först sedan årsprofilen räknats fram en första gång, vilket kräver minst 30 dygns data: samma mognadsgräns som ett fullt betyg (avsnitt 4). En ny anläggning räknar alltså om vid varje push tills den passerat 30 dygn. Data ni skickar utöver dygnstaket lagras direkt, men utlöser ingen ny omräkning av årsprofilen.
Datatäckning
GET /partner/plants (se nedan) visar hur mycket data Wolta har fått in per
anläggning: first_hour, last_hour och n_days (antalet distinkta lokala dygn
med data, räknat tidszonsmedvetet och alltså inte som antal timmar delat med 24).
Använd det för att upptäcka luckor i er datamatning.
curl -s "https://wolta.se/api/v1/partner/plants?limit=100&offset=0" \
-H "Authorization: Bearer wpk_din-nyckel-här"
{
"plants": [
{
"client_plant_id": "exb-001",
"zone": "SE3",
"control_system": "other",
"first_hour": "2026-07-01T00:00:00+00:00",
"last_hour": "2026-08-01T23:00:00+00:00",
"n_days": 32,
"grade_status": "ok"
},
{
"client_plant_id": "exb-002",
"zone": "SE3",
"control_system": "other",
"first_hour": null,
"last_hour": null,
"n_days": 0,
"grade_status": "none"
}
],
"total": 2
}
total är hela er flotta, inte antalet rader på sidan. limit måste vara > 0
(annars 422) och klipps tyst till 500: ett limit=100000 ger 500 rader
tillbaka, inte ett fel. Sidindela med offset.
Se avsnitt 4 för den fullständiga statusvokabulären. grade_status här och
status i GET /partner/grades använder samma vokabulär och kan aldrig motsäga
varandra för samma anläggning.
Batterigränser
Wolta gör en fysikalisk rimlighetskontroll per klocktimme för att fånga omöjliga
batteriflöden, till exempel en kumulativ mätare hos er som nollställts eller hoppat.
Överskrider en lagrad timmes totala laddning eller urladdning 1,5 × anläggningens
effekt × 1 timme nollställs batteriflödena för den timmen automatiskt. Solcells- och
nätflöden bevaras. Effekten som räknas är den högsta av battery_kw och en
eventuell lagrad märkeffekt (nameplate_kw).
repaired_battery_rows i svaret visar hur många lagrade timrader som åtgärdades.
- 0: Allt normalt, ingen åtgärd.
- > 0: Minst en timme hade omöjliga batterivärden. Åtgärder:
- Kontrollera sensorernas konfiguration (
battery_kw-värdet korrekt?). - Leta efter hopp i era egna loggar (kumulativ mätare som nollställts eller brutits).
- Om datan är korrekt kan ni skicka den igen. En senare korrekt omsändning ersätter de nollställda värdena (upsert-semantiken ovan).
- Kontrollera sensorernas konfiguration (
4. Läsa betyg
Betygen läser ni för hela flottan i taget. Avsnittet går igenom endpointen, vad ett tomt betyg betyder och den statusvokabulär som talar om varför en anläggning ännu saknar betyg.
Batch-läsning
GET /partner/grades läser senaste betyg för alla era anläggningar i en
paginerad batch. Samma sidregler som /partner/plants: limit måste vara > 0
och klipps tyst till 500.
curl -s "https://wolta.se/api/v1/partner/grades?limit=100&offset=0" \
-H "Authorization: Bearer wpk_din-nyckel-här"
{
"grades": [
{
"client_plant_id": "exb-001",
"score": 62,
"status": "ok",
"period_start": "2026-07-01",
"period_end": "2026-08-01",
"grade_version": "3"
},
{
"client_plant_id": "exb-002",
"score": null,
"status": "collecting",
"period_start": "2026-08-01",
"period_end": "2026-08-04",
"grade_version": "3"
}
],
"total": 2
}
score är null för alla statusar utom ok (se tabellen nedan). Bygg er
integration så att den hanterar null som “inget att visa än”, inte som ett fel.
Ett negativt betyg visas aldrig som en siffra, se below_baseline nedan. Wolta
svarar hellre null än med ett tal som kan misstolkas.
period_start/period_end är all data Wolta någonsin fått inlagrad för
anläggningen (samma täckning som first_hour/last_hour i /partner/plants,
fast datumprecision), inte nödvändigtvis exakt det fönster som senaste
betygsberäkningen räknade på. Tolka fälten som “sedan när har vi er data”,
inte som en exakt beräkningsperiod.
grade_version visar vilken version av betygslogiken som ligger bakom siffran
(i dag "3"). Ändras logiken, vilket sker då och då vid till exempel nya
viktningsmodeller, höjs versionen och betygen räknas om. Jämför inte betyg med
olika grade_version rakt av över tid utan att veta vad som ändrades.
Varje läsning av /grades (och av /plants) uppdaterar också anläggningarnas
“senast använd”-status internt. Det håller flottan aktiv för fortsatta
omräkningar även om ni bara läser betyg utan att skicka ny data en period.
Betygsstatusar
GET /partner/plants (fältet grade_status) och GET /partner/grades
(fältet status) delar en gemensam vokabulär. Båda härleds ur samma två lagrade
värden, antalet dygn med data och det lagrade betyget, och kan därför aldrig visa
olika lägen för samma anläggning:
| Status | Innebörd | score i /grades |
|---|---|---|
none |
Mindre än 7 dygns data. Inget betyg alls ännu. | null |
collecting |
7–29 dygns data. För tidigt för ett betyg, anläggningen väntar bara på att nå 30 dygn. | null |
check_data |
30+ dygns data, men Wolta har ännu inte kunnat visa ett säkert betyg. Tre möjliga orsaker (se nedan). | null |
below_baseline |
Klarade rimlighetskontrollen, men nettobetyget är negativt: styrningen presterade sämre än ett passivt batteri, efter slitage. En ärlig signal, men visas aldrig som en siffra. | null |
ok |
Klarade rimlighetskontrollen, betyget är noll eller positivt. Fullt betyg. | betyget, 0–105 |
check_data betyder att inget säkert betyg är tillgängligt ännu. Bakom statusen
ligger tre möjliga orsaker, och Wolta kan i dagsläget inte skilja dem åt i
statusfältet:
- Nyligen mogen, omräkningen har inte hunnit köra. Anläggningen passerade nyss 30-dygnsgränsen, men det dagliga betygssvepet (se avsnitt 3) har ännu inte bearbetat den. Det kan ta upp till ett dygn efter att gränsen passerats. Inget datafel, bara en tidsfråga: vänta in nästa svep innan ni antar något annat.
- Tvivelaktig indata. Rimlighetskontrollen underkände datan (t.ex. en inverterad sensormappning eller en omöjlig energibalans). Kontrollera sensorernas polaritet/enheter för denna anläggning.
- Legitim modell-fallback. Anläggningen har gott om data, men modellen saknar tillräckligt ekonomiskt underlag för ett säkert betyg (vanligast vid litet batteri eller låg prisvolatilitet i zonen under fönstret). Det är inte ett tecken på trasig data eller dålig prestanda, bara att Wolta hellre avstår från att gissa.
Ge svepet ett par dygn efter att anläggningen passerat 30 dygn innan ni misstänker
en sensorbugg. Kvarstår check_data längre än så är det er datamatning ni ska
granska först. Statusen är i sig inget bevis på att anläggningen presterar dåligt.
below_baseline är något annat: ett giltigt, om än lågt, betyg. Styrningen kan
förbättras, men datan i sig är trovärdig. check_data handlar om att inget säkert
betyg alls gick att räkna fram.
Betyg uppdateras efter dygnssvepen (se avsnitt 3), inte i realtid när ni
pushar data. Skicka data → vänta till nästa svep (någon gång under
eftermiddagen, svensk tid) → läs uppdaterat betyg. Ett betyg som redan nått ok
ändras inte bara för att ni pushar ny data mellan svepen. Det ligger kvar tills
nästa svep räknar om det.
Er flotta i jämförelsedatan
Anläggningar ni matar in ingår i Woltas jämförelsekorpus: underlaget bakom medianen och percentilerna som betygen ställs mot. Flottan viktas ned så att en enskild partner inte kan flytta jämförelsen: bidraget är takat till en andel av den totala vikten, oavsett hur många anläggningar ni har. Vill ni stå utanför korpusen helt går det att stänga av per partner. Hör av er (avsnitt 8).
5. Slutkundslänkar
Varje anläggning får vid skapande en link_token (prefix wpl_, se avsnitt 2).
Av den bygger ni en personlig länk in till wolta.se, där slutkunden, alltså
anläggningens ägare, kan se sitt betyg och redigera sina egna fält: ekonomi
(inköpspris och inköpsdatum för batteri och solceller), elavtal/tariff,
betygsfönster och anläggningens visningsnamn. De tekniska fälten
(batteristorlek, effekt, verkningsgrad, styrsystem, zon) förblir alltid partnerns.
Slutkunden kan aldrig ändra dem, och partnerns API kan aldrig skriva över
slutkundens ekonomi/tariff-val.
Länken ser ut så här:
https://wolta.se/anlaggning?link=wpl_slutkundens-token-här
Slutkunden ser hela anläggningsvyn med betyg, ekonomi, utbyggnadssimulering och anläggningsdata, precis som en vanlig användare. De tekniska fälten visas låsta, med er som förvaltare, och vyn hänvisar slutkunden till er för ändringar av anläggningsdata och för radering. Radering går alltså via ert API (avsnitt 2), aldrig via länken.
Dela länken privat med slutkunden. Länken är i sig nyckeln: den som har den kommer åt anläggningen, utan inloggning. Behöver ni återkalla den, se rotationen nedan.
Ett undantag från fältuppdelningen: stegvis batteriköp (battery_events)
kan varken ni eller slutkunden sätta via era respektive vägar. Fältet ser ut som
ekonomi men styr härledd batterikapacitet, alltså teknisk data, och ligger därmed
utanför både partner-API:t och länken. Det går bara att ändra via ägarens egna
vägar: en inloggad Wolta-session, eller anläggningens profil-token, som är skild
från slutkundslänkens wpl_-token ovan. I praktiken är bara session-vägen öppen,
eftersom en partner aldrig får ut anläggningens profil-token. Slutkunden kan
fortfarande ange sitt inköpspris och inköpsdatum som vanligt.
Rotation
Misstänker ni att en länk-token läckt, eller vill ge en ny slutkund en färsk länk för en anläggning som bytt ägare, roterar ni:
curl -s -X POST https://wolta.se/api/v1/partner/plants/exb-001/link/rotate \
-H "Authorization: Bearer wpk_din-nyckel-här" \
-H "Content-Length: 0"
Svar:
{"link_token": "wpl_nyare-token-här"}
Den gamla token slutar fungera omedelbart och den som öppnar den gamla länken möts av en “länken fungerar inte längre”-sida. Det finns bara en giltig länk-token per anläggning åt gången. Detsamma gäller om anläggningen raderas eller om er partner-nyckel stängs av: alla flottans länkar slocknar då.
Rotation finns medvetet inte som knapp i partnerportalen. En rotation släcker länkar ni redan delat ut till slutkunder, så den ska vara ett medvetet API-anrop från er integration, inte ett klick.
6. Felkoder
Alla felsvar ligger under nyckeln detail (se avsnitt 2). Tabellen täcker de
statuskoder partner-API:t svarar med och vad ni gör åt dem.
| Kod | Betydelse | Åtgärd |
|---|---|---|
| 401 | Saknad eller ogiltig Authorization-header, eller okänd nyckel. |
Kontrollera att headern är exakt Authorization: Bearer wpk_... och att nyckeln är korrekt inklistrad (inga extra mellanslag/radbrytningar). |
| 403 | Nyckeln är giltig men partnern är avstängd, eller ett PATCH-anrop försökte sätta ett fält som ägs av slutkunden (t.ex. cost_sek). Svaret bär då {"detail": {"error": "field_not_partner_owned", "field": "..."}}. |
Vid avstängd partner: kontakta Wolta (avsnitt 8). Vid fältfel: ta bort det otillåtna fältet ur PATCH-kroppen. Det ändras via slutkundslänken i stället, inte via partner-API:t. |
| 404 | Okänd client_plant_id för er partner (eller en annan partners anläggning – ni ser aldrig andra partners data). |
Kontrollera att client_plant_id stavas rätt och att anläggningen faktiskt skapats med POST /partner/plants först. |
| 409 | {"detail": {"error": "plant_limit_reached", "plant_limit": ...}} vid POST /partner/plants (tier-gränsen är nådd). |
Radera en oanvänd anläggning, eller begär tier-uppgradering (avsnitt 8). |
| 413 | För många rader i en POST .../data-batch (fler än 5 000), kroppen överstiger 2 MiB rått, eller anläggningens totala lagringstak (80 000 rader) är nått. |
Dela upp stora batchar i flera mindre anrop. Vid lagringstaket: skapa en ny anläggning. |
| 422 | Valideringsfel: ogiltig zone ("zonen stöds inte ännu", eller ett försök att ändra en redan satt zon, se avsnitt 2), ogiltigt control_system ("okänt styrsystem" vid POST /partner/plants, "okänt styrsystem: <värde>" vid PATCH /partner/plants/{client_plant_id} – PATCH-vägen ekar det inskickade värdet, skapande gör det inte), saknade obligatoriska fält vid skapande, numeriska värden utanför gränserna, ett client_plant_id som inte är URL-säkert eller är längre än 128 tecken (se avsnitt 2), null på ett partnerägt PATCH-fält, eller trasig/naiv ts_utc i en datapush. |
Rätta fältet enligt felmeddelandet. Kontrollera särskilt att alla tidsstämplar har Z eller offset. |
| 429 | Rate-budgeten (rate_max_per_min från /partner/me) är förbrukad. Headern Retry-After anger sekunder att vänta. |
Vänta angiven tid, försök igen. Sprid ut anrop jämnare över tid om detta händer ofta. |
ts_utc kan underkännas på två sätt, med olika meddelanden. Båda pekar ut vilken
rad i batchen som orsakade felet. Radnumret är nollindexerat: rad 2 är alltså
tredje raden i den rows-lista ni skickade.
- Saknad tidszon – en i övrigt giltig tidsstämpel utan
Z/offset (naiv lokaltid, t.ex.2026-08-01T00:00:00):"rad 2: ts_utc saknar tidszon - ange offset eller Z". - Trasig sträng – går inte att tolka som ISO 8601 över huvud taget:
"rad 2: ogiltig tidsstämpel '...'", där den mottagna strängen citeras rakt av i meddelandet.
7. Portalen
wolta.se/partner/portal är er självbetjäningsvy. Samma adress täcker hela vägen in. Är ni inte inloggade möts ni av formuläret för e-post och länk (avsnitt 1). Har ni klickat länken i mejlet landar ni antingen på registreringsformuläret, om kontot ännu inte har någon partner, eller direkt på översikten, om det redan har en. Är partnern avstängd visas en banner om det, och era API-anrop svarar 403.
Översikt är förstasidan. Överst ligger flottans samlade betyg: medianen av era
anläggningars betyg och spridningen (lägsta–högsta). Båda visas först när minst två
anläggningar har ett fullt betyg (status ok). Anläggningar i below_baseline,
check_data, collecting eller none räknas inte in, eftersom de inte har något
tal att räkna på. Under betyget visas en rad nyckeltal: antal anläggningar mot er
plant_limit, hur många som strömmar (data inkommen de senaste 48 timmarna), hur
många som har fullt betyg, och tidpunkten för den senaste timme Wolta tagit emot
från någon av era anläggningar.
Problem att åtgärda listar de anläggningar som behöver uppmärksamhet, räknade per problemkod. Koderna är portalens egna och finns inte i partner-API:t, så bygg ingen integration mot dem:
| Kod | Betyder | Vad ni gör |
|---|---|---|
stopped_streaming |
Senast mottagna timme är äldre än 48 timmar. | Kontrollera att er synk mot just den anläggningen fortfarande kör. |
never_streamed |
Anläggningen har aldrig fått en enda timme, och skapades för mer än 7 dygn sedan. | Antingen är onboardingen ofärdig, eller så ska anläggningen raderas (avsnitt 2) så den slutar uppta en plats i tier-gränsen. Anläggningar yngre än 7 dygn flaggas inte alls – ni ska inte mötas av varningar för något ni skapade i förrgår. |
future_timestamp |
Senast mottagna timme ligger i framtiden. | Klockan eller tidszonshanteringen i er integration är fel. Se tidsstämpelkravet i avsnitt 3. |
ingest_gaps |
Ett eller flera avslutade dygn helt utan timmar, inne i anläggningens faktiska strömningsperiod. | Leta luckor i er synk. Dygn före anläggningens första data, dygn efter att strömningen upphört, och innevarande (ofullständiga) dygn räknas aldrig som luckor. |
check_data |
Samma sak som betygsstatusen check_data (avsnitt 4). |
Räknas i statusfördelningen men inte i problemlistan – se avsnitt 4 för de tre möjliga orsakerna. |
below_baseline är medvetet inte en problemkod. Det är ett ärligt mätvärde, inte
ett fel i er datamatning.
Status per anläggning visar hur flottan fördelar sig över betygsstatusarna i
avsnitt 4. Summan är alltid hela flottan, så en flotta där halva ligger i
collecting syns här även när problemlistan är tom.
Inflöde, hela flottan är ett stapeldiagram med en stapel per dygn över de senaste 7 dygnen. Stapeln visar antalet mottagna timmar, normaliserat mot hur många anläggningar som hunnit börja strömma just det dygnet.
Anläggningar ligger bakom knappen “Visa alla anläggningar”. En rad per anläggning:
client_plant_id, zon, styrsystem, betygsstatus och betyg (samma vokabulär och samma
siffra som GET /partner/grades), tidpunkt för senast mottagna timme, en stapel per
dygn över de senaste 7 dygnen, och radens problemkoder. Dygnen räknas i
anläggningens egen tidszon. Det är den snabbaste vägen att se vilken anläggning
som slutat leverera.
Företagsuppgifter är ett hopfällt, helt frivilligt formulär: kontaktperson, e-post, telefon, hemsida, organisationsnummer och adress (gata, postnummer, ort, land). Uppgifterna används bara av Wolta, för att kunna nå er och för fakturering vid kommersiell drift, och visas aldrig publikt eller för era slutkunder. Bara de fält ni faktiskt ändrar skrivs; ett tomt fält betyder “inte angivet”. (Företagsnamnet ni angav vid registreringen är ett undantag: det visas för slutkunden i den anläggningsvy länken i avsnitt 5 leder till, som namnet på förvaltaren.)
Nyckelrotation. Ni roterar er wpk_-nyckel själva. Den gamla nyckeln slutar
fungera omedelbart, och pågående integrationer som fortfarande använder den får
401. Den nya visas i klartext en gång.
Alla partner registrerar sig inte själva: vi lägger också upp partner manuellt när ett avtal kräver det, till exempel med andra gränser än testnivåns. En sådan partner har inget Wolta-konto kopplat och därmed ingen portal. Nyckelrotation, ändrade gränser och avstängning sköter vi då åt er på begäran. Har ni registrerat er själva gäller portalen i stället, och ni behöver aldrig höra av er för att rotera en nyckel.
Slutkundslänkarna (wpl_) hanteras däremot inte i portalen. De lagras bara
hashade, så portalen kan inte visa en befintlig länk igen, och en rotation släcker
länkar ni redan delat ut. Rotation sker därför via API:t
(POST /partner/plants/{client_plant_id}/link/rotate, avsnitt 5), som ett medvetet
anrop från er integration.
8. Support och ändringar
Frågor, problem eller behov av ändringar (tier-uppgradering, höjd rate-budget, avstängning, korpusmedlemskap): kontakta [email protected].
Kommersiell drift, alltså fler anläggningar än dev-free-tierns 10 eller högre rate-budget än 120 anrop per minut, hanteras manuellt i dag. Ange företagsnamn, önskat antal anläggningar och önskad budget i er förfrågan.
Nyckelrotation behöver ni inte höra av er om: det gör ni själva i portalen (avsnitt 7).