Advanced setup

Use Getting started for standard client setup. This page covers what the client does for you, optional platform services and client customization.

What the client does for you

Behaviour What happens
Retries The client retries reads (GET) that fail with a 5xx up to 5 times with exponential backoff, except a 504: a gateway gave up waiting on a slow request, and asking again repeats the slow work. On Android, iOS and the JVM it also retries reads after a failed connection, and on Android and the JVM after a connect timeout. A read that times out waiting for the server is not retried, since the server may still be working on it. Do not add your own retry loop around 5xx responses to reads. Mutations (POST, PUT, DELETE) are sent once: when one fails with a 5xx or its response never arrives, the server may already have applied it, and sending it again could apply it twice. The exception is a request with an Idempotency-Key header, which the client retries like a read. Only invoice direct send accepts one, and the integrated-document helpers carry their own key, so after any other failed write, read the resource before you try again.
Rate limits On a 429 the client waits for Retry-After (1 s when the header is missing) and tries again, up to 5 times, then throws RateLimitException (TypeScript: SoliboApiError without status). This covers mutations too: a 429 means the server did not process the request. The waits count toward the request timeout, so if you shorten it, a long Retry-After can end the call with a timeout error instead.
Timeouts The server decides how long a request may run, so the client’s own limits are generous: a request may take 500 s, and on Android, iOS and the JVM it may also go 500 s without receiving data. Connecting may take 5 s on Android and the JVM; on iOS the 500 s limit covers connecting too. In TypeScript only the 500 s request limit applies. You can shorten them for a client, as shown below.
Request bodies Before sending, the SDK removes null values, blank strings and empty objects from request bodies, so the API treats them as omitted. You cannot clear a field by sending null or an empty string.
HTTP cache Each client keeps an in-memory HTTP cache for its lifetime and revalidates GETs with the ETag response header, so you do not handle ETags yourself. (meta.etag in a page is a different value, for comparing pages.) The cache has no size limit; in long-running jobs that page through large data sets, create a fresh client per run.
Session refresh mobile refreshes the token envelope by itself on a 401, and m2m fetches a new token once the current one is 15 minutes old. browser never refreshes on its own: on a 401, call await sdk.auth.refresh() once and retry. When the server refuses the refresh token, the SDK clears its stored session and then runs the refresh failure handler. A NO_SESSION or CREDENTIAL_REJECTED reason refuses it; without a reason, a 401, 400, 404, or 422 does. Other statuses, server errors and network failures keep the session.
Session storage In Kotlin, the SDK keeps its session (token envelope, refresh token, user id and language) in settings. By default that is plain platform key-value storage (SharedPreferences, NSUserDefaults, Java Preferences); pass an encrypted store in production apps, for example KeychainSettings on iOS. In TypeScript, the session lives in localStorage in browsers (for mobile that includes the refresh token) and in memory on Node, and the store cannot be replaced.
Language Requests ask for Norwegian (Accept-Language: nb-NO first) by default, so validation messages arrive in Norwegian. For English, set sdk.api.userLanguage = "en-US" (TypeScript: sdk.raw.api.userLanguage = 'en-US').
Base URL In TypeScript, baseUrl names a host and the client appends /api (https://home.solibo.no becomes https://home.solibo.no/api). Leave it out to use https://api.home.solibo.no, which is used as it is; use https://home.solibo.no for cookie sessions. In Kotlin, sdk.api.setInitialBaseUrl(url) takes the full URL, /api included.

Authentication environments

Each session kind maps to a TypeScript auth.kind, a React authMode and a Kotlin factory; see the table in Getting started. Keep machine-client secrets on the server.

Advanced configuration (Kotlin)

Use the builder callback to customize Ktor or handle an expired session:

import io.ktor.client.plugins.HttpTimeout
import no.solibo.oss.sdk.SoliboSDK

val sdk = SoliboSDK.createMobile(
    userPoolId = "USER_POOL_ID",
    clientId = "CLIENT_ID"
) {
    httpClientConfig = {
        // The defaults are 500 s per request, 500 s without data and 5 s to connect.
        install(HttpTimeout) {
            requestTimeoutMillis = 60_000
            socketTimeoutMillis = 30_000
        }
    }
    onRefreshFailure = {
        // Clear application session state and show the login screen.
    }
}

Your HttpTimeout settings apply to this client only and replace the defaults they name; the ones you leave out keep their default.

The SDK calls onRefreshFailure after it clears the stored tokens, once the server refuses the refresh token. When the server sends a reason, it decides: NO_SESSION and CREDENTIAL_REJECTED end the session. Without one, a 401, 400, 404, or 422 from the refresh endpoint does. Any other status, server errors, and network failures keep the session, so a later request can refresh again. With token auth, auth.refresh() throws a SoliboSDKError whenever the refresh fails, including after the session has ended.

Platform implementations (Kotlin)

Supply these adapters when your application needs them:

Adapter Implement Purpose
Fingerprinter print(username: String): String Return encoded Cognito security context from the platform’s AWS library.
PushTokenProvider suspend fun token(): String? Return the device’s push token, or null when unavailable.

Both interfaces are in no.solibo.oss.sdk.auth and default to no-op implementations. Pass your implementations to the factory:

val sdk = SoliboSDK.createMobile(
    userPoolId = "USER_POOL_ID",
    clientId = "CLIENT_ID",
    fingerprinter = appFingerprinter,
    pushTokenProvider = appPushTokenProvider
)

appFingerprinter and appPushTokenProvider are your platform adapters. For iOS, provide implementations through your shared KMP module.

Advanced configuration (React / TypeScript)

Add refreshFailureHandler to redirect users when their session expires. It runs when the refresh endpoint rejects the session; a browser client refreshes only when you call await sdk.auth.refresh() after a 401.

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

const sdk = createSoliboClient({
  baseUrl: 'https://home.solibo.no',
  auth: {
    kind: 'browser',
    userPoolId: 'USER_POOL_ID',
    clientId: 'CLIENT_ID',
    credentials: 'include',
  },
  refreshFailureHandler: {
    onRefreshFailure: () => {
      // Clear any application session state here.
      window.location.assign('https://home.solibo.no/auth/login?next=' + encodeURIComponent(window.location.href));
    },
  },
});

The same handler can be added to a SoliboProvider configuration. If you use Cognito security context data, provide a fingerprinter object whose print(username) method returns the encoded context string.

Error handling

Error types for Kotlin, TypeScript and React are in Errors.


Solibo AS