Models and State

BagIdConfig

Configuration provided to BagIdSdk.configure().

  • Kotlin

  • Swift

data class BagIdConfig(
    val apiBaseUrl: String,
    val sourceAppKey: String,
    val tokenProvider: suspend () -> String,
    val theme: BagIdTheme? = null,
    val localization: BagIdLocalization? = null,
)
// The Kotlin `suspend () -> String` is exposed as an `async throws` closure.
let config = BagIdConfig(
    apiBaseUrl: "https://api.bagid.com",
    sourceAppKey: "your-issued-client-key",
    tokenProvider: { try await AuthBridge.federatedToken() },
    theme: nil,
    localization: nil
)
Field Type Description

apiBaseUrl

String

Base URL of the BagID API (e.g., "https://api.bagid.com").

sourceAppKey

String

Issued client key for request authorization and routing.

tokenProvider

suspend () → String

Function that returns a federated identity token on demand. Called silently by the SDK whenever authentication or re-authentication is needed.

theme

BagIdTheme?

Optional styling for future or product-specific SDK UI surfaces (reserved; core transfer/clear flows are headless today).

localization

BagIdLocalization?

Optional locale and string overrides (reserved alongside theme).

BagIdTheme

  • Kotlin

  • Swift

data class BagIdTheme(
    val primaryColor: String? = null,
    val backgroundColor: String? = null,
    val textColor: String? = null,
    val errorColor: String? = null,
    val fontFamily: String? = null,
    val borderRadius: Int? = null,
    val inputStyle: InputStyle? = null,
    val buttonStyle: ButtonStyle? = null,
)

enum class InputStyle { OUTLINED, FILLED, UNDERLINED }
enum class ButtonStyle { FILLED, OUTLINED, TEXT }
// Nullable Int in Kotlin is bridged as `KotlinInt?` in Swift.
let theme = BagIdTheme(
    primaryColor: "#003366",
    backgroundColor: "#FFFFFF",
    textColor: "#111111",
    errorColor: "#B00020",
    fontFamily: "System",
    borderRadius: 8,
    inputStyle: .outlined,
    buttonStyle: .filled
)

All fields are optional. Unset fields use SDK defaults. Colors are hex strings (e.g., "#003366").

BagIdLocalization

  • Kotlin

  • Swift

data class BagIdLocalization(
    val locale: String? = null,
    val overrides: Map<String, String>? = null,
)
let localization = BagIdLocalization(
    locale: "nb-NO",
    overrides: [
        "verification.title": "Bekreft eier"
    ]
)
Field Type Description

locale

String?

BCP 47 language tag (e.g., "nb-NO", "en", "sv"). Falls back to "en" if unsupported.

overrides

Map<String, String>?

Per-string overrides keyed by string ID. Supports interpolation variables like {{remaining}} and {{maskedSurname}}.

InitResult

  • Kotlin

  • Swift

sealed class InitResult {
    data object Authenticated : InitResult()
    data class Unavailable(val reason: UnavailableReason) : InitResult()
}

enum class UnavailableReason {
    TOKEN_PROVIDER_FAILED,
    FEDERATION_REJECTED,
    NETWORK_ERROR,
}
// Exhaustive matching on the sealed class via SKIE's onEnum(of:).
switch onEnum(of: result) {
case .authenticated:
    break // continue
case .unavailable(let unavailable):
    switch unavailable.reason {
    case .tokenProviderFailed: print("Token provider failed")
    case .federationRejected:  print("Federation rejected")
    case .networkError:        print("Network error")
    }
}

LoadJourneyRequest

  • Kotlin

  • Swift

sealed class LoadJourneyRequest {
    data class Bcbp(val scanData: String, val airline: String? = null) : LoadJourneyRequest()
    data class AirlinePayload(
        val passengers: List<AirlinePassenger>,
    ) : LoadJourneyRequest()
}
// Construct either variant through its nested type:
let bcbpRequest: LoadJourneyRequest = LoadJourneyRequestBcbp(scanData: "M1SNOW/JON...", airline: nil)

let airlineRequest: LoadJourneyRequest = LoadJourneyRequestAirlinePayload(
    passengers: [airlinePassenger]
)

AirlinePassenger

  • Kotlin

  • Swift

data class AirlinePassenger(
    val passenger: Passenger,
    val pnr: String,
    val surname: String,
    val flights: List<FlightInfo>,
    val baggage: List<AirlineBaggageInput>? = null,
)
let airlinePassenger = AirlinePassenger(
    passenger: Passenger(surname: "Snow", givenName: "Jon", title: "Mr"),
    pnr: "A13712",
    surname: "Snow",
    flights: [flightInfo],
    baggage: nil
)

Journey

Returned by loadJourney, createBaggageTag, and createAirlineBaggage.

  • Kotlin

  • Swift

data class Journey(
    val journeyId: Int,
    val passengers: List<Passenger>,
    val flights: List<FlightInfo>,
    val baggage: List<BaggageRecord>,
)
// `Int32` in Swift because Kotlin `Int` bridges to 32-bit.
let journeyId: Int32 = journey.journeyId
let passengers: [Passenger] = journey.passengers
let flights: [FlightInfo] = journey.flights
let baggage: [BaggageRecord] = journey.baggage

Passenger

  • Kotlin

  • Swift

data class Passenger(
    val surname: String? = null,
    val givenName: String? = null,
    val title: String? = null,
)
let passenger = Passenger(
    surname: "Snow",
    givenName: "Jon",
    title: "Mr"
)

FlightInfo

  • Kotlin

  • Swift

data class FlightInfo(
    val flightNumber: String,
    val departureAirport: String,
    val destinationAirport: String,
    val departureAt: String?,
)
let flight = FlightInfo(
    flightNumber: "WF459",
    departureAirport: "BGO",
    destinationAirport: "OSL",
    departureAt: "2023-01-21T10:00:00+01:00"
)

BaggageRecord

  • Kotlin

  • Swift

data class BaggageRecord(
    val baggageId: Int,
    val baggageTagNumber: String?,
    val airline: String?,
    val destinationAirport: String?,
)
let id: Int32 = baggage.baggageId
let tag: String? = baggage.baggageTagNumber
let airline: String? = baggage.airline
let destination: String? = baggage.destinationAirport

CreateBaggageTagRequest

  • Kotlin

  • Swift

data class CreateBaggageTagRequest(
    val journeyId: Int,
    val passengerList: List<Passenger>,
)
let request = CreateBaggageTagRequest(
    journeyId: journey.journeyId,
    passengerList: [passenger]
)

CreateAirlineBaggageRequest

  • Kotlin

  • Swift

data class CreateAirlineBaggageRequest(
    val journeyId: Int,
    val baggageTagNumber: String,
    val airline: String,
    val destinationAirport: String,
)
let request = CreateAirlineBaggageRequest(
    journeyId: journey.journeyId,
    baggageTagNumber: "0701913714",
    airline: "WF",
    destinationAirport: "OSL"
)

BagIdScanEvent

Scan results from BagIdSdk.scanForEbtTags() / scanForEbtTags(deviceId). Cold flow: collection starts the scan; cancelling stops it.

  • Kotlin

  • Swift

sealed class BagIdScanEvent : ScanEvent {
    data class DeviceFound(val device: DiscoveredEbtBleDevice) : BagIdScanEvent(), ScanEvent.DeviceFound
    data class ScanError(override val message: String) : BagIdScanEvent(), ScanEvent.ScanError
}
for await event in BagIdSdk.shared.scanForEbtTags() {
    switch onEnum(of: event) {
    case .deviceFound(let e):
        print("Found: \(e.device.deviceId)")
    case .scanError(let e):
        print("Scan error: \(e.message)")
    }
}

Only one scan collector should run at a time; starting another while the first is active may emit ScanError asking you to cancel the previous flow.

DiscoveredEbtBleDevice

One row from BLE discovery (after the SDK classifies the advertisement).

  • Kotlin

  • Swift

data class DiscoveredEbtBleDevice(
    val identity: EbtTagIdentity,
    val deviceId: String,
    val signalStrength: Int,
)
let id: String = device.deviceId
let rssi: Int32 = device.signalStrength
let identity: EbtTagIdentity = device.identity
  • deviceId — Android: address-style id from the stack; iOS: CoreBluetooth peripheral identifier (string).

  • signalStrength — RSSI in dBm.

  • identity — vendor / hardware class the SDK inferred (see EbtTagIdentity).

EbtTagIdentity

Vendor and hardware class for an EBT. The SDK uses this to route to the correct internal BLE implementation; hosts normally only display it or pass discovery context via notifyDiscoveredModel.

  • Kotlin

sealed class EbtTagIdentity {
    data class BagId(val model: BagIdDeviceType) : EbtTagIdentity()
    data class BagIdBleV21(val model: BagIdDeviceType) : EbtTagIdentity()
    data class OtherVendor(val modelHint: String?) : EbtTagIdentity()
}

BagIdDeviceType

BagID hardware line (from advertising / identity):

  • Kotlin

enum class BagIdDeviceType {
    BAGID_GO,
    BAGID_2FM,
    BAGID_2ST,
}

ConnectedEbtDevice

Full BLE connection snapshot (see BagIdSdk.ebtBleDeviceState).

  • Kotlin

data class ConnectedEbtDevice(
    val uuid: String,
    val deviceId: String,
    val identity: EbtTagIdentity,
    val batteryLevel: Int?,
    val firmwareVersion: FirmwareVersion?,
    val serialNumber: String?,
)

Use uuid as TransferTagRequest.uniqueDeviceId / ClearTagRequest.uniqueDeviceId when it matches your backend device id (see transfer docs).

FirmwareVersion

BLE-reported firmware (com.bagid.sdk.ble.bagidEbt.domain.FirmwareVersion):

data class FirmwareVersion(val major: Int, val minor: Int, val revision: Int)
// toString() -> "major.minor.revision"

EbtBleDeviceState

  • Kotlin

data class EbtBleDeviceState(
    val connectedDevice: ConnectedEbtDevice?,
    val lastError: String?,
)

Emitted by BagIdSdk.ebtBleDeviceState; BLE errors are also mirrored into BagIdState.bleLastError.

TransferTagRequest

  • Kotlin

  • Swift

data class TransferTagRequest(
    val deviceId: String,
    val uniqueDeviceId: String,
    val baggageId: Int,
    val journeyId: Int,
    val recordLocator: String? = null,
    val custodyProofSurname: String? = null,
    val displayTicket: EbtTicket? = null,
    val journey: Journey? = null,
)
let request = TransferTagRequest(
    deviceId: selectedDevice.deviceId,
    uniqueDeviceId: connected.uuid,
    baggageId: baggage.baggageId,
    journeyId: journey.journeyId,
    recordLocator: nil,
    custodyProofSurname: nil,
    displayTicket: nil,
    journey: journey
)

Provide either displayTicket or a journey that contains baggageId, so the SDK can build the BLE ticket. When the lock lookup requires custody proof, supply recordLocator and custodyProofSurname (uppercase surname as required by the API), or handle CustodyProofRequiredException and retry.

TransferResult

  • Kotlin

  • Swift

data class TransferResult(
    val bleWriteSuccess: Boolean,
    val attachmentSuccess: Boolean,
    val pendingRetry: Boolean,
    val device: DeviceInfo,
)
let wrote: Bool = transfer.bleWriteSuccess
let attached: Bool = transfer.attachmentSuccess
let pending: Bool = transfer.pendingRetry
let device: DeviceInfo = transfer.device

pendingRetry is true when the BLE write succeeded but device attachment HTTP failed. The host can surface this for retry or support follow-up; there is no separate attachment queue in the SDK beyond this flag.

ClearTagRequest

  • Kotlin

  • Swift

data class ClearTagRequest(
    val deviceId: String,
    val uniqueDeviceId: String,
)
let request = ClearTagRequest(
    deviceId: selectedDevice.deviceId,
    uniqueDeviceId: connected.uuid
)

ClearResult

  • Kotlin

  • Swift

data class ClearResult(
    val success: Boolean,
    val unlocked: Boolean,
)
let success: Bool = result.success
let unlocked: Bool = result.unlocked

DeviceInfo

  • Kotlin

  • Swift

data class DeviceInfo(
    val deviceId: String,
    val serialNumber: String?,
    val batteryLevel: Int?,
    val firmwareVersion: String?,
)
let deviceId: String = info.deviceId
let serial: String? = info.serialNumber
let battery: Int? = info.batteryLevel.map { Int(truncating: $0) }   // KotlinInt? → Int?
let firmware: String? = info.firmwareVersion

BagIdState

Observable state emitted by BagIdSdk.state.

  • Kotlin

  • Swift

data class BagIdState(
    val authenticated: Boolean,
    val sessionExpired: Boolean,
    val connectedDevice: DeviceInfo?,
    val lastError: String?,
    val bleLastError: String?,
    val identifiedEbtTagIdentity: EbtTagIdentity? = null,
)
// `StateFlow<BagIdState>` is bridged to `AsyncSequence` by SKIE.
for await state in BagIdSdk.shared.state {
    let authenticated: Bool = state.authenticated
    let sessionExpired: Bool = state.sessionExpired
    let device: DeviceInfo? = state.connectedDevice
    let lastError: String? = state.lastError
    let bleLastError: String? = state.bleLastError
    let tagIdentity: EbtTagIdentity? = state.identifiedEbtTagIdentity
}
  • lastError — HTTP / orchestration failures from façade APIs.

  • bleLastError — last error from ebtBleDeviceState.

  • identifiedEbtTagIdentity — from notifyDiscoveredModel and refreshed after connect.

EbtType and vendor BLE extras

EbtType selects vendor-specific optional BLE features that are not on the core façade (nametag is one example today for EbtType.BagId via EbtBleExtras). It does not choose which physical tag you have—that comes from BLE discovery (EbtTagIdentity).

sealed class EbtType {
    data object BagId : EbtType()
}

interface EbtBleExtras {
    suspend fun sendNametag(header: String, imageBytes: ByteArray): Result<Unit>
}