HBL API – Dokumentation

Detta API används för att beräkna och presentera bolåneerbjudanden, samt exponera marknadsräntor (list- och snitträntor) per bindningstid. Dokumentet beskriver autentisering, endpoints, request/response-format samt centrala affärsregler (inklusive rule_deviation).

Base URL:
Auth: x-api-key
Format: JSON

Översikt

Alla API-svar returneras som JSON. API:t är skyddat med API-nyckel via HTTP-header. Rekommenderad användning är att klienten hämtar marknadsräntor (rates-endpoints) separat från individuella beräkningar (calculate).

Observera: Endpoints under /api kräver giltig x-api-key.

Autentisering

Ange API-nyckeln i headern x-api-key. Om nyckeln saknas eller är felaktig returneras 401 Unauthorized.

HEADER x-api-key: <DIN_NYCKEL>
API-nyckel måste skickas i varje anrop till /api/*.

Exempel (curl)

curl -X GET "/api/rates/list" \
  -H "x-api-key: DIN_API_KEY"

Vanliga statuskoder

200OK
400Felaktig input (t.ex. calculate)
401Unauthorized (saknad/fel API-key)
500Internt fel

Felhantering

API:t returnerar fel som JSON med error-fält (och ibland extra detaljer). Klienten bör hantera 4xx som användar-/inputfel och 5xx som tillfälliga serverfel.

ERROR Exempel: 401 / 400 / 500
Standardiserad felrespons.

Felrespons (exempel)

{
  "error": "Unauthorized"
}

Rekommenderad klientlogik

401 Verifiera att x-api-key skickas korrekt.
400 Visa valideringsfel. (Ex: saknade fält eller ogiltiga värden.)
500 Visa generellt fel och tillåt “försök igen”. Logga request-id om tillgängligt.

GET /api/form/questions

Returnerar konfigurerade formulärfrågor (t.ex. rabatter) som kan användas i UI för att bygga dynamiska val. Resultatet används främst för att bygga selected_discounts till /api/calculate.

GET /api/form/questions
Formulärmetadata (frågor, typer, grupper, sortering).

Exempel (curl)

curl -X GET "/api/form/questions" \
  -H "x-api-key: DIN_API_KEY"

Response

{
  "questions": [
    {
      "id": 1,
      "key": "IKEA_Family",
      "label": "IKEA Family medlem?",
      "type": "checkbox",
      "group": "discounts",
      "options": null,
      "active": true,
      "sortOrder": 3
    },
    {
      "id": 2,
      "key": "TCO_Saco_HSB_SPP",
      "label": "Välj ett alternativ (Saco/TCO, HSB Bospar, SPP)",
      "type": "select",
      "group": "discounts",
      "options": ["TCO", "Saco", "HSB", "SPP"],
      "active": true,
      "sortOrder": 10
    }
  ]
}
questions array Lista med frågeobjekt. Rendera endast active=true.
questions[].id number Unikt id för frågan.
questions[].key string Unik nyckel. Skickas som värde i selected_discounts.
questions[].label string Text som visas i UI.
questions[].type string UI-typ, t.ex. checkbox, select, radio, number.
questions[].group string Gruppering i UI (t.ex. discounts). Använd för sektioner/headers.
questions[].options array | null Alternativ för select/radio. null för checkbox.
questions[].active boolean Om frågan ska visas i UI.
questions[].sortOrder number Sorteringsordning inom grupp.
Rendering (rekommenderat)
  • Filtrera: questions.filter(q => q.active)
  • Sortera: sort((a,b) => a.sortOrder - b.sortOrder)
  • Gruppera på group (t.ex. “Rabatter”)
  • Bygg UI utifrån type: checkbox → checkbox, select → dropdown, radio → radiogrupp
  • Skicka valda key-värden till /api/calculate som selected_discounts.
Exempel: payload-utdrag
{
  "selected_discounts": ["IKEA_Family", "TCO"],
  "monthly_spend": 3000
}
Obs Om en fråga kräver extra input (t.ex. ICA_Stammismonthly_spend), visa/hide det fältet baserat på om dess key är vald.

POST /api/calculate

Beräknar fram räntan man kan få för en specifik förfrågan baserat på lånebeloppets storlek, belåningsgrad, bindningstid, övriga rabatter och bankregler. Responsen sorterar alltid lägsta ränta överst och banker med rule_deviation längst ner.

POST /api/calculate
Personlig jämförelse: räntor, kostnader, amortering, ev. besparing samt rule_deviation.

Request

{
  "loan_amount": 2700000,
  "property_value": 4500000,
  "property_type": "Bostadsratt",
  "term": "ThreeMonth",
  "current_rate": 0,
  "selected_discounts": ["IKEA_Family"],
  "monthly_spend": 0,
  "energy_class": "Vet ej"
}
loan_amount number Ja Lånebelopp i kronor.
property_value number Ja Bostadens uppskattade marknadsvärde.
property_type string Ja Bostadstyp.
term string Ja Bindningstid.
current_rate number Villkor Nuvarande bolåneränta"
selected_discounts string[] Nej Valda rabatter
monthly_spend number Villkor Krävs avICA_Stammis
energy_class string Nej Bostadens energiklass

Exempel (curl)

curl -X POST "/api/calculate" \
  -H "Content-Type: application/json" \
  -H "x-api-key: DIN_API_KEY" \
  -d '{
    "loan_amount": 2700000,
    "property_value": 4500000,
    "property_type": "Bostadsratt",
    "term": "ThreeMonth",
    "current_rate": 0,
    "selected_discounts": ["IKEA_Family"],
    "monthly_spend": 0,
    "energy_class": "Vet ej"
  }'

Response (exempel)

{
  "results": [
    {
      "bankId": 1,
      "bankName": "Exempelbank",
      "logo": "...",
      "utm_link_move": "https://...",

      "fixed_rate": 3.95,
      "average_rate": 3.80,
      "personal_rate": 3.65,
      "total_discount": -0.30,
      "effective_rate": 3.72,

      "monthly_interest_cost": 8200,
      "monthly_amortization": 4500,
      "amortization_percentage": 1,

      "total_monthly_cost_before_tax": 12700,
      "monthly_tax_deduction": 2050,
      "total_monthly_cost_after_tax_deduction": 10650,

      "loan_amount": 2700000,
      "property_value": 4500000,
      "ltv": 60,
      "down_payment": 1800000,

      "current_rate": null,
      "monthly_savings_before_tax": null,
      "monthly_savings_after_tax": null,

      "green_mortgage": false,
      "rule_deviation": null,

      "open_price_model": true,
      "agreement": "..."
    }
  ]
}

Fält (urval)

personal_ratePersonlig ränta efter tillämpliga rabatter (om möjligt). number|null
average_rateBankens snittränta (kan vara fallback). number|null
fixed_rateBankens listränta / grundränta. number|null
rule_deviationMeddelande-lista om banken inte kan ge korrekt erbjudande (visas utan räntedata). string[]|null
total_monthly_cost_before_taxTotal månadskostnad före skatteavdrag. number|null

GET /api/rates/list

Returnerar listräntor (Fixed) per bank, grupperat per bindningstid (term). Banker sorteras med lägsta listränta först inom varje term.

GET /api/rates/list
Listränta per bank och term. (Stabelo exkluderas från Fixed enligt affärsregel.)

Exempel (curl)

curl -X GET "/api/rates/list" \
  -H "x-api-key: DIN_API_KEY"

Response

{
  "terms": {
    "ThreeMonth": [
      { "bankId": 2, "bankName": "Bank A", "fixed_rate": 3.95 },
      { "bankId": 7, "bankName": "Bank B", "fixed_rate": 4.05 }
    ],
    "OneYear": [
      { "bankId": 7, "bankName": "Bank B", "fixed_rate": 3.85 }
    ]
  }
}
terms object Nyckel per term (bindningstid).
terms[].bankId number Unikt bank-ID.
terms[].bankName string Bankens namn.
terms[].fixed_rate number Listränta (Fixed) i procent. Sorterad lägst först per term.
terms[].last_updated Date/String Senast ändrade listränta hos banken.

GET /api/rates/average

Returnerar snittränta per term (aggregerat över banker som har giltig Average-ränta för termen). Detta är en marknadsindikator – ingen banklista i denna endpoint.

GET /api/rates/average
Snittränta per bindningstid (term), baserat på bankers Average-rader.

Exempel (curl)

curl -X GET "/api/rates/average" \
  -H "x-api-key: DIN_API_KEY"

Response

{
  "terms": {
    "ThreeMonth": { "average_rate": 2.65, "banks": 13 },
    "OneYear":    { "average_rate": 2.80, "banks": 13 },
    "FiveYear":   { "average_rate": 2.20, "banks": 13 }
  }
}
terms object Nyckel per term.
terms[].average_rate number Snittränta (Average) i procent, avrundad till två decimaler.
terms[].banks number Antal banker som ingår i snittet för termen.

GET /api/rates/average-per-bank

Returnerar snittränta (Average) per bank och term, grupperat per bindningstid. Banker sorteras med lägsta snittränta först inom varje term.

GET /api/rates/average-per-bank
Snittränta per bank och term (Average). Används för per-bank tabeller/grafer.

Exempel (curl)

curl -X GET "/api/rates/average-per-bank" \
  -H "x-api-key: DIN_API_KEY"

Response

{
  "terms": {
    "ThreeMonth": [
      { "bankId": 2, "bankName": "Bank A", "average_rate": 2.35 },
      { "bankId": 7, "bankName": "Bank B", "average_rate": 2.55 }
    ],
    "OneYear": [
      { "bankId": 7, "bankName": "Bank B", "average_rate": 2.75 }
    ]
  }
}
terms object Nyckel per term (bindningstid).
terms[].bankId number Unikt bank-ID.
terms[].bankName string Bankens namn.
terms[].average_rate number Bankens snittränta (Average) i procent.

rule_deviation

rule_deviation används när en bank inte kan ge ett korrekt prissatt erbjudande för indata (t.ex. otillåten bostadstyp, belåningsgrad utanför regelverk, eller bank kräver manuell kontakt). När rule_deviation finns ska klienten visa meddelandet och inte visa räntedata för banken.

Frontend-rekommendation: Om rule_deviation är en array med minst ett element, visa endast första meddelandet som och dölja räntor/kostnader.

Sortering

Calculate-resultat sorteras av API:t: banker utan rule_deviation först, sedan lägsta ränta (personal → average → fixed). Banker med rule_deviation returneras sist.

Rates-endpoints: inom varje term sorteras banklistor stigande på respektive ränta (lägst först).

Affärsregler (urval)

Nedan regler påverkar datat:

Fritidshus Vissa banker kan exkludera Fritidshus via regler och då sätts rule_deviation i calculate.
Rabatter Rabatter drivs via selected_discounts, monthly_spend (ICA) och energy_class (green mortgage).
Amortering Baseras på belåningsgrad (LTV): >70% = 2%, >50% = 1%, annars 0% (i beräkningslogik).