Changelog

Patch releases without an entry track backend contract updates: the clients and models are regenerated, and there are no SDK-level API changes. A contract update can bring new subtypes and enum values, and an older SDK can fail on a response that carries one it does not know, so upgrade regularly; see Compatibility. Contract changes and deprecations are listed on the developer portal’s API changes page.

Unreleased

  • A refresh token the server refuses now ends the session: the SDK clears the stored tokens and calls onRefreshFailure instead of retrying the same token on every 401. The server’s reason decides when it sends one (NO_SESSION or CREDENTIAL_REJECTED); otherwise a 400, 404, or 422 does. Other statuses, server errors, and network failures keep the session.
  • With token auth, auth.refresh() throws a SoliboSDKError when the server refuses the refresh token, after ending the session. A 401 from the refresh endpoint now throws too, where it used to return.
  • When Cognito issues a device key and registering the device fails, sign-in fails with DeviceRegistrationException and the tokens it had stored are cleared, so nobody is left signed in without a registered device. A push token that cannot be fetched no longer fails sign-in; the device is registered without one.
  • Added usePublicDocumentURL(params), the cached query form of the public document URL, and usePublicConversationDocumentURL(params) with its factory publicConversationDocumentURLQueryOptions(sdk, params) for public conversation documents. Components that show the same picture share one request, and the hooks stay idle until every id is set. The conversation variant always asks for the URL, because that endpoint redirects by default. usePublicGetDocumentURL remains for downloads; every call is a new request.
  • showDocumentUrls and showPublicDocumentUrls on api.documents sign up to 100 document URLs in one request and return them as a paged list, each with its expiresAt; pass autoPaginate: true to get them all at once. documentURLsQueryOptions / useDocumentURLs and publicDocumentURLsQueryOptions / usePublicDocumentURLs wrap them, and MockHomeApi answers both.
  • useGetDocumentURL, usePublicDocumentURL, and usePublicGetDocumentURL send the lookups a screen makes together as one of those requests per company and image rendition, so a page of pictures costs one request instead of one each. Their cache keys are unchanged. A lookup made alone, or with fields, keeps the single-document endpoint, and a document the batch leaves out fails with a 404 as before.
  • FailureReason.DEVICE_REJECTED, sent when device sign-in cannot verify the remembered device, is classified as a DEFECT, as the bare 404 it replaces was. Sign-in then fails with DeviceRejectedException: the SDK forgets the device, and the next email or SMS sign-in sends hasDeviceSecret: false, so it finishes without a device challenge and registers a fresh device.
  • FailureReason.INVOICING_NOT_ACTIVE, sent by the company invoicing routes when invoicing is not activated, is classified as the new FailureKind.FEATURE_OFF rather than a DEFECT: the app should show that invoicing is off. Kotlin code with an exhaustive when over FailureKind needs a branch for it.
  • The client no longer retries mutations. A POST, PUT, or DELETE that fails with a 5xx or a network error is sent once, because the server may already have applied it: retrying could send a letter or an invoice twice, or replay a one-time code. Reads are retried as before, and so is a request with an Idempotency-Key header (invoice direct send) or a 429 response, which the server did not process. After a failed write, read the resource before you try again.
  • Added pushNotificationTypesQueryOptions / usePushNotificationTypes for the new api.communication.indexPushNotificationTypes, which lists every push notification type with the payload fields it carries. Push inbox items have a typed payload, null when the server matches no type: NewOppslagPushPayload, NewPracticalInfoPushPayload, NewMessageInConversationPushPayload, NewNeighborhoodPostPushPayload, or NewCommunicationCommentPushPayload. MockHomeApi answers the inbox and the type list.
  • The optimistic updates of useCreateIssueToMeeting and useRemoveIssueFromMeeting (and their *MutationOptions) now reach the data useMeeting and useIssues show: the issue enters or leaves every cached copy of the meeting, and its status changes on every loaded page of the company’s issue lists. They used to write to cache keys no query reads, and adding an issue with withoutOptimisticUpdate: false failed with a TypeError before the request was sent. Without beforeIndex, the new issue shows last. If the request fails, the queries are refetched as before.
  • Breaking for useSectionStatus readers: sectionStatusQueryOptions / useSectionStatus return the section’s statuses keyed by section id and then by status state (SectionStatusesBySection), as the backend now sends them, so data[state] becomes data[sectionId][state]. api.sections.showSectionStatus returns the matching nested Map.
  • upcomingInvoicingQueryOptions / useUpcomingInvoicing take companyIds to limit the invoicing preview to some housing communities; leave it out to include every one you can access. Kotlin’s indexUpcomingInvoicing takes companyIds as its last argument, so positional calls keep their meaning.
  • The optimistic update of useCreateConversationMessage (and createConversationMessageMutationOptions) now reaches the data useConversation shows: the message appears at once in every cached copy of the conversation, whatever its translateToCountryId or fields, and useConversationMessageHistory is left alone. It used to look for a cache key no query reads. The message has the shape of a fetched MessageInConversation from the current user (sentByCurrentUser: true, and sentById from useUser, or -1 before the user has loaded), with a negative placeholder id and sentAt as an ISO 8601 string. What only the server knows, such as type, sentBy, and documents, is null until the refetch replaces the message. If the request fails, the conversation is refetched as before.
  • conversationQueryOptions and useConversation() no longer retry a conversation the server refuses with a 4xx other than 408, 425, or 429. The check compared the error itself to 404 rather than its status, so a missing conversation was requested four times per refetch.
  • Homepage no longer has feed or practicalInformation, because the backend stopped sending them: showHomepage / useHomepage return the company and its image. Load the posts with useHomepageFeed and useHomepagePracticalInformation, or useOpenHomepageFeed and useOpenHomepagePracticalInformation for an open homepage.
  • Requests are no longer cut off at 30 s; the host in front of the backend decides how long one may run. A request may now take 500 s and go 500 s without data (15 s before, on Android, iOS and the JVM); connecting may still take 5 s. Shorten them per client with install(HttpTimeout) in httpClientConfig. A read is no longer retried after a read timeout or a 504, because the server may still be working on it; failed connections and other 5xx responses are retried as before.
  • Conversation attachments can be kept in the internal (board-only) thread: pass visibility: 'INTERNAL' to useUploadDocumentBelongsTo(), useMultiUploadDocument(), or useCreateDocumentReference() (and their ...MutationOptions factories). Without it the backend treats the upload as PUBLIC, so files added to an internal message showed up in the public conversation.
  • An integrated document mutation that the backend refuses during finalization (a 4xx other than 408, 425 or 429) now fails at once with outcomeUnknown = false and removes its uploads. Through HomeApi.integratedDocuments such a refusal used to be retried and then reported as an unknown outcome with the uploads kept, because the client’s response validator threw SoliboSDKError before the helper could read the status. IntegratedDocumentMutationException now has statusCode, the status of the refusal, and its cause is the SoliboSDKError with the backend’s error details.

1.20.2 (2026-09-25)

  • The JavaScript packages (@solibo/solibo-sdk and @solibo/home-api) ship ws 8.21.3 for GHSA-96hv-2xvq-fx4p.

1.20.0 (2026-09-24)

  • JavaScript behaviour change for client.raw callers: the JavaScript package converts collections at its boundary everywhere, so callers only use JS values. Arrays, Maps, and plain objects go into client.raw.api.* methods, model constructors, and setters; arrays and Maps come back from getters, HttpResponse.body(), HttpResponse.headers, callbacks, and helpers such as createUploadHeaders. A model constructed from JS reads back as JS, and a model received from the SDK can be handed back unchanged. No API signature refers to KtList or KtMap any more; KtList.fromJsArray / KtMap.fromJsMap remain exported for backwards compatibility but are never required.
  • *WithDocumentsMutationOptions and use*WithDocuments() no longer fail with attachments.iterator_... is not a function, and client.api.accounting.* accepts companyIds, accountNumbers, projectIds, departmentIds, and supplierIds again.

1.19.0

1.18.0

  • Published the Sentry artifact, no.solibo.oss:sdk-sentry, for Android and iOS.
  • Exported the route templates used by telemetry to the JavaScript package.

1.17.1

  • Wrapped the bank account lists and the meeting summons PDF.
  • Added spamConversation and spamMultipleConversations, and their unspam* counterparts, so a caller can flag a conversation as spam.
  • Decoded the server’s refusal reason into the contract’s enum.
  • Built the iOS Sentry framework as a static framework.

1.17.0

  • Instrumented every API call in OpenTelemetry’s terms. Install a provider with SoliboOpenTelemetry.install(openTelemetry); the SDK bundles only the api and noop artifacts.
  • Added the sdk-sentry artifact, which enriches the host application’s Sentry with the SDK’s spans (installSoliboSentryTelemetry()).
  • SoliboSDKError now carries the kind of failure and the server’s reason, so callers can switch on why the server refused.
  • Optional fields tolerate values they did not expect instead of failing the whole response.

1.16.18

  • Updated Kotlin, Fabrikt, Ktor, the Android Gradle plugin, AWS and logging dependencies.

1.16.17

  • Generation converts the backend’s OpenAPI 3.1 contract to 3.0 before code generation, matching the backend’s move to OpenAPI 3.1.1.

1.16.15

  • Query key factories trim trailing undefined arguments, fixing invalidation of keys built with optional parameters.

1.16.14

  • Every OpenAPI parameter is forwarded through the solibo-query and solibo-react wrappers; callers now control parameters the wrappers previously pinned.

1.16.9

  • Fixed the serialization test contract.

1.16.4

  • Added supplier comment edit and delete wrappers.

1.16.0

  • Toolchain and contract compatibility updates.

1.15.13

  • Shared enum compatibility fixes.

1.14.0

  • Fixed direct-password and SRP login returning NEW_PASSWORD as failed credentials instead of a pending challenge.
  • Preserved reset-code and MFA flows and the Boolean confirmation API. Log in again after confirmation, and call Auth.clearSession() when cancelling the challenge UI.

1.13.0

  • Added company and multi-company accounting reads for overviews, projects and entries through HomeApi.accounting and SoliboClient.api.accounting.
  • Added five dedicated query factories and React hooks with scoped cache keys, cursor pagination and field selection.
  • Preserved exact monetary strings and company coverage metadata, including in Kotlin response projections.

1.10.0

  • Added generated SDK, query-option, and React-hook coverage for homepage comments and neighborhood communication.
  • Added atomic document convenience helpers for neighborhood posts and homepage/neighborhood comments, including cover-image retention and document removal on post updates.
  • Added a dedicated homepage feed-post query for refreshing comment and reaction state.

1.9.0

Layered JavaScript API

The npm packages now expose one abstraction layer each:

  • @solibo/solibo-sdk owns the JavaScript client, generated models, authentication, event bus, and raw Kotlin interop.
  • @solibo/solibo-query owns framework-independent TanStack Query option factories, query keys, pagination helpers, and mutation definitions.
  • @solibo/solibo-react owns SoliboProvider, useSdk(), and React hooks.

SoliboClient is the JavaScript-native SDK surface. Its generated API methods take one named-parameter object and return the decoded response body. The unchanged Kotlin-generated client is available through client.raw and the @solibo/solibo-sdk/interop entry point when response status, headers, redirects, downloads, or another low-level capability is required.

import { createSoliboClient } from '@solibo/solibo-sdk'

const client = createSoliboClient({
  baseUrl: 'https://home.solibo.no',
  auth: {
    kind: 'browser',
    userPoolId: '...',
    clientId: '...',
  },
})

const company = await client.api.companies.showCompany({ companyId })

// Explicit escape hatch: positional parameters and HttpResponse<T>.
const response = await client.raw.api.companies.showCompany(BigInt(companyId))

JavaScript migration list

Before Now
sdk.api.companies.showCompany(BigInt(companyId)).then(r => r.body()) client.api.companies.showCompany({ companyId })
Pass a raw SoliboSDK to a query factory Pass fromRawSdk(rawSdk), or the client returned by createSoliboClient(...)
Import SDK models from @solibo/solibo-query or @solibo/solibo-react Import them from @solibo/solibo-sdk
Import query factories or keys from @solibo/solibo-react Import them from @solibo/solibo-query
Import hooks from a lower package Import hooks from @solibo/solibo-react
Use a facade call when status or headers matter Use client.raw, which preserves HttpResponse<T> and request-header controls
Import low-level Kotlin bridge or upload helpers from @solibo/solibo-query Use the SDK facade/raw DocumentsApi, or a query mutation factory for the complete flow
Import toIntegratedDocumentInput or prepareIntegratedDocumentSources from @solibo/solibo-query Pass document sources to a *WithDocumentsMutationOptions factory, or use client.raw.api.integratedDocuments for the low-level composite API

The root @solibo/solibo-sdk entry point retains its previous raw KMP exports, so existing direct SDK imports and positional calls continue to compile. The explicit client.raw property makes the low-level boundary visible in new code.


Solibo AS