← Tilbake til dokumentasjon

API Referanse

REST API for bygningsenergisimulering med Bemify

Bemify Simulation API lar deg laste opp en SIMIEN Pro-modell (.sxi) og få tilbake energiresultater, energimerke (A–G) og TEK17-samsvarskontroll. API-et bruker en asynkron jobbkø — du sender inn en simulering og poller for resultater.

Base URL: https://api.bemify.no

Se kildekoden på GitHub

Hurtigstart

# Kjør en simulering med klimadata fra server
curl -X POST https://api.bemify.no/simulate \
  -H "Authorization: Bearer bmf_YOUR_TOKEN" \
  -F "model=@building.sxi" \
  -F "klimasted=Oslo"

# Poll for resultater
curl https://api.bemify.no/job/job_123456_1 \
  -H "Authorization: Bearer bmf_YOUR_TOKEN"

Autentisering

Alle simuleringsendepunkter krever en Bearer-token i Authorization-headeren:

Authorization: Bearer bmf_YOUR_TOKEN

Kontakt erlend@bemify.no for API-tilgang.

Endepunkter

POST /simulate

Start en ny simulering. Returnerer en jobb-ID for polling.

Content-Type: multipart/form-data

ParameterTypePåkrevdBeskrivelse
modelfilJaSIMIEN Pro prosjektfil (.sxi)
climatefilBetingetEnergyPlus værfil (.epw). Gjensidig eksklusiv med klimasted. Ikke tillatt for tek17 og energimerke.
klimastedstrengBetingetKommunenavn (f.eks. Oslo). Alternativ til climate. Ikke tillatt for tek17.
simuleringstypestrengNeiaarssimulering (standard), energimerke, eller tek17

Regler for klimadata

  • Oppgi enten klimasted eller climate-fil, ikke begge
  • For tek17: Klimadata hentes alltid automatisk (TEK17-referanseklima). Oppgi ikke klimasted eller climate — forespørselen avvises med 400.
  • For energimerke: Kun klimasted godtas — EPW-filer avvises med 400. Energimerking krever en standard norsk klimasone for klimakorreksjonsfaktoren.
  • Bruk GET /klimasteder for å se gyldige kommunenavn.

Respons (202):

{
  "jobId": "job_1712832645123_1",
  "position": 1,
  "message": "Simulering lagt i kø (posisjon 1). Poll /job/job_1712832645123_1 for status."
}

GET /job/:jobId

Sjekk jobbstatus og hent resultater. Krever autentisering. Brukere kan kun se egne jobber.

Statuser: queued | running | completed | error

Respons ved fullført (200):

{
  "jobId": "job_1712832645123_1",
  "status": "completed",
  "queuedAt": "2026-04-11T10:30:45.123Z",
  "startedAt": "2026-04-11T10:30:50.456Z",
  "completedAt": "2026-04-11T10:32:15.789Z",
  "result": {
    "beregningspunkter": { "netto": { ... }, "brutto": { ... }, "tilfort": { ... }, "levert": { ... } },
    "zones": [{ "id": "sone-1", "navn": "Sone 1", "area": 150.0 }],
    "energimerke": { ... },
    "tek17": { ... }
  }
}

Respons ved feil (200):

{
  "jobId": "job_1712832645123_1",
  "status": "error",
  "completedAt": "2026-04-11T10:32:15.789Z",
  "error": "Feilmelding"
}

Merk: Resultater beholdes i opptil 30 minutter etter fullføring, men kan slettes tidligere dersom kapasitetsgrensen nås.

GET /klimasteder

Liste over alle tilgjengelige klimasteder. Ingen autentisering påkrevd.

{
  "locations": ["TEK17 Referanseklima", "Oslo", "Bergen", "Trondheim", ...],
  "count": 51
}

GET /health

Helsesjekk for serveren. Ingen autentisering påkrevd.

{
  "status": "ok",
  "timestamp": "2026-04-11T10:30:45.123Z",
  "queue": { "length": 0, "processing": false }
}

GET /queue

Køstatus. Ingen autentisering påkrevd.

{ "queueLength": 0, "isProcessing": false }

Simuleringstyper

VerdiBeskrivelseKlimadataEkstra resultatfelt
aarssimuleringHelårssimulering (standard)klimasted eller EPWenergimerke
energimerkeEnergimerkingKun klimastedenergimerke
tek17TEK17-samsvarskontrollAutomatisk (referanseklima)energimerke, tek17

Resultatformat

Beregningspunkter (result.beregningspunkter)

Resultatene grupperes i fire beregningspunkter iht. NS 3031:

PunktNøkkelBeskrivelse
AnettoNetto energibehov (bygningens behov)
BbruttoBrutto energibehov (inkl. systemtap)
CtilfortTilført energi (fra energikilder)
DlevertLevert energi (fra nett/energibærere)

Hvert beregningspunkt inneholder energyResults med årstotaler per energipost (romoppvarming, ventilasjonsvarme, varmtvann, kjøling, belysning, utstyr m.m.).

Energimerke (result.energimerke)

Beregnes automatisk når prosjektet har gyldig kommune og bygningskategori.

{
  "energimerke": "B",
  "totalArea": 250.0,
  "korreksjonsfaktor": 1.05,
  "klimakorrigertVektetSpesifikk": 92.3,
  "sumVektetSpesifikk": 96.9,
  "sumLevertEnergi": 24075,
  "sumSpesifikk": 96.3,
  "vektetKlimaavhengig": 42.1,
  "vektetIkkeKlimaavhengig": 54.8,
  "items": [
    {
      "kilde": "1 Levert elektrisitet",
      "levertEnergi_kWh": 21500,
      "spesifikk_kWhm2": 86.0,
      "vektingsfaktor": 1.0,
      "vektetSpesifikk_kWhm2": 86.0
    }
  ]
}
FeltEnhetBeskrivelse
energimerkeA–GEnergikarakter
klimakorrigertVektetSpesifikkkWh/(m²·år)Klimakorrigert vektet spesifikk levert energi (bestemmer karakteren)
sumVektetSpesifikkkWh/(m²·år)Vektet spesifikk levert energi (før klimakorreksjon)
sumLevertEnergikWh/årTotal levert energi
korreksjonsfaktorKlimakorreksjonsfaktor for kommune/bygningstype
itemsarrayFordeling per energibærer

TEK17-validering (result.tek17)

Kun tilgjengelig når simuleringstype=tek17.

{
  "erSamsvarsende": true,
  "energiramme": {
    "poster": [
      { "post": "1a", "beskrivelse": "Romoppvarming", "spesifikk_kWhm2": 12.3 }
    ],
    "totalBeregnet": 105.2,
    "forskriftskrav": 115.0,
    "status": "oppfylt",
    "bygningskategori": "Kontorbygning"
  },
  "minstekrav": {
    "rader": [
      { "bygningsdel": "U-verdi yttervegger", "faktiskVerdi": 0.18, "kravVerdi": 0.22, "status": "oppfylt" }
    ],
    "samletStatus": "oppfylt"
  },
  "luftmengder": {
    "rader": [
      { "beskrivelse": "Spesifikk vifteeffekt (SFP)", "faktiskVerdi": 1.50, "kravVerdi": 2.00, "status": "oppfylt" }
    ],
    "samletStatus": "oppfylt"
  },
  "energiforsyning": {
    "brukerFossilBrensel": false,
    "fossilKilder": [],
    "punkt2Gjelder": true,
    "harSentralVarmesentral": true,
    "sentralAndelProsent": 85.2,
    "status": "oppfylt"
  },
  "oppsummering": {
    "antallOppfylt": 4,
    "antallIkkeOppfylt": 0,
    "antallIkkeRelevant": 0
  }
}

Mulige status-verdier: "oppfylt", "ikke_oppfylt", "ikke_relevant".

Feilkoder

KodeBetydningEksempel
400Ugyldig forespørselManglende modellfil, ugyldig simuleringstype, både klimasted og climate oppgitt
401Ikke autorisertManglende Authorization-header
403ForbudtUgyldig eller deaktivert API-nøkkel
404Ikke funnetJobb ikke funnet eller utløpt
413For storFil overstiger 10 MB-grensen
429For mange forespørslerGlobal eller per-nøkkel rate-grense nådd, eller for mange aktive jobber
502Bad gatewayKunne ikke hente klimadata fra oppstrømstjeneste
503Kø fullMaks 20 samtidige jobber

Begrensninger

GrenseVerdi
Global rate-grense30 forespørsler per minutt
Per-nøkkel POST /simulate6 forespørsler per minutt
Per-nøkkel GET /job/:jobId120 forespørsler per minutt
Maks aktive jobber per nøkkel3
Maks filstørrelse10 MB per fil
Maks kødybde20 jobber
Simuleringstimeout10 minutter
Resultat-TTL30 minutter

Eksempler

curl

# Standard simulering med kommuneklima
curl -X POST https://api.bemify.no/simulate \
  -H "Authorization: Bearer bmf_YOUR_TOKEN" \
  -F "model=@building.sxi" \
  -F "klimasted=Oslo"

# Energimerkesimulering
curl -X POST https://api.bemify.no/simulate \
  -H "Authorization: Bearer bmf_YOUR_TOKEN" \
  -F "model=@building.sxi" \
  -F "klimasted=Oslo" \
  -F "simuleringstype=energimerke"

# TEK17-samsvarskontroll (klimadata hentes automatisk)
curl -X POST https://api.bemify.no/simulate \
  -H "Authorization: Bearer bmf_YOUR_TOKEN" \
  -F "model=@building.sxi" \
  -F "simuleringstype=tek17"

# Simulering med egen EPW-fil
curl -X POST https://api.bemify.no/simulate \
  -H "Authorization: Bearer bmf_YOUR_TOKEN" \
  -F "model=@building.sxi" \
  -F "climate=@oslo.epw"

# Poll for resultater
curl https://api.bemify.no/job/job_123456_1 \
  -H "Authorization: Bearer bmf_YOUR_TOKEN"

Python

import requests
import time

API_URL = "https://api.bemify.no"
TOKEN = "bmf_YOUR_TOKEN"
headers = {"Authorization": f"Bearer {TOKEN}"}

# Start simulering
with open("building.sxi", "rb") as model:
    resp = requests.post(
        f"{API_URL}/simulate",
        headers=headers,
        files={"model": model},
        data={"klimasted": "Oslo", "simuleringstype": "energimerke"},
    )

job_id = resp.json()["jobId"]
print(f"Jobb startet: {job_id}")

# Poll for resultater
while True:
    status = requests.get(f"{API_URL}/job/{job_id}", headers=headers).json()
    if status["status"] in ("completed", "error"):
        break
    print(f"Status: {status['status']}...")
    time.sleep(2)

if status["status"] == "completed":
    result = status["result"]

    # Energimerke
    if "energimerke" in result:
        em = result["energimerke"]
        print(f"Energimerke: {em['energimerke']}")
        print(f"Vektet spesifikk: {em['klimakorrigertVektetSpesifikk']:.1f} kWh/(m²·år)")

    # TEK17 (kun for simuleringstype=tek17)
    if "tek17" in result:
        tek = result["tek17"]
        print(f"TEK17-samsvar: {tek['erSamsvarsende']}")
else:
    print(f"Feil: {status['error']}")