Swift SDK

The ChatBotKit Swift SDK is the official Swift library for the ChatBotKit API. Use it to add streaming AI chat to iOS, macOS, tvOS, watchOS and visionOS apps, or to call the API from Swift on a server or on Linux. It is built on URLSession with async/await and has no third-party dependencies.

Key Features

  • Native concurrency: every call is async, streams are AsyncThrowingStreams, and cancelling a Task cancels the request; the client is Sendable and checked by the Swift 6 compiler, so one instance can be shared across tasks
  • Streaming chat: receive the bot reply token by token
  • Generated types: Codable and Sendable request and response types generated from the API specification
  • Session tokens: apps talk to ChatBotKit with a short-lived token and never hold the API secret
  • Typed errors and retries: FetchError with the API error code, retries with backoff on 429 and 5xx responses
  • Linux support: works with FoundationNetworking, so the same code runs in server-side Swift

Requirements

  • Swift 6.0 or later (Xcode 16 or later)
  • iOS 15, macOS 12, tvOS 15, watchOS 8, visionOS 1, or Linux

Installation

Add the package with Swift Package Manager:

dependencies: [ .package(url: "https://github.com/chatbotkit/swift-sdk", from: "0.1.0"), ], targets: [ .target(name: "MyApp", dependencies: [ .product(name: "ChatBotKit", package: "swift-sdk"), ]), ]

swift

In Xcode, choose File > Add Package Dependencies and enter the same URL.

Quick Start

import ChatBotKit let client = ChatBotKit(token: "your-api-secret") let conversation = try await client.conversation.create( ConversationCreateRequest(backstory: "You are a helpful assistant.", model: "gpt-4o") ) let reply = try await client.conversation.complete( conversation.id, ConversationMessageCompleteRequest(text: "Hello!") ).value print(reply.text)

swift

Streaming

Calls that can stream return a ResponsePromise. Await .value for the JSON response, or iterate .stream() to receive the events as they arrive:

let stream = client.conversation.complete( conversation.id, ConversationMessageCompleteRequest(text: "Tell me a story") ).stream() for try await item in stream { switch item.type { case .token: print(item.data.token ?? "", terminator: "") case .result: print("\nDone") default: break } }

swift

Stateless completions, where you send the full history and nothing is stored, work the same way:

let stream = client.conversation.complete( ConversationCompleteRequest( messages: [ConversationCompleteRequestMessage(text: "Hi!", type: .user)], model: "gpt-4o" ) ).stream()

swift

Breaking out of the loop or cancelling the surrounding task cancels the request. To handle event types that the typed stream item does not describe yet, stream them as StreamEvent, which keeps the raw type and data:

for try await event in client.conversation.receive(conversationId).stream(as: StreamEvent.self) { print(event.type, event.data) }

swift

List calls stream too, which is the simplest way to walk through every item:

for try await item in client.bot.list().stream() { print(item.data.id) }

swift

Session Tokens for Mobile Apps

Never ship your API secret inside an app - it can be extracted from the binary. Keep the secret on your server and give the app a short-lived session token for a single conversation.

On your server, with any ChatBotKit SDK:

let server = ChatBotKit(token: ProcessInfo.processInfo.environment["CHATBOTKIT_API_SECRET"]!) // a new conversation with a bot let session = try await server.bot.session.create("bot-id") // or an existing conversation let existing = try await server.conversation.session.create( conversationId, ConversationSessionCreateRequest(durationInSeconds: 3600) )

swift

Return the conversation ID, token and expiresAt to the app, which then uses only the token:

let client = ChatBotKit(token: sessionToken) for try await item in client.conversation.complete(conversationId, ConversationMessageCompleteRequest(text: "Hi")).stream() { // update the UI }

swift

A conversation session token can complete, send and receive messages, upload attachments and vote on messages of that one conversation. Everything else, such as listing conversations or reading the message history, goes through your server. Tokens last one hour by default and at most a day, so request a new one before expiresAt.

Configuration

let client = ChatBotKit( options: ChatBotKitOptions( token: "your-api-secret", baseURL: URL(string: "https://api.chatbotkit.com")!, runAsUserId: "user-id", timezone: "Europe/London", headers: ["X-App-Version": "1.0"], timeout: 60, retries: 3, retryDelay: 0.25 ) )

swift

OptionDescription
tokenAPI secret (server) or session token (app). secret is an alias.
baseURLAPI base URL, e.g. http://localhost:3000 for a self-hosted platform.
hostReplaces the host of baseURL.
runAsUserIdRun requests as a sub-user.
timezoneSent with every request as X-Timezone.
headersExtra headers for every request.
timeoutRequest timeout in seconds.
retriesRetries after network errors and 429/5xx responses (default 3).
retryDelayDelay before the first retry in seconds; doubles each time.
sessionThe URLSession to use.

Resources

The client mirrors the structure of the Node SDK:

ClientOperations
client.conversationlist, fetch, create, update, delete, complete, dispatch, send, receive, votes
client.conversation.messagelist, fetch, create, update, delete, upvote, downvote
client.conversation.sessioncreate
client.conversation.attachmentlist, upload
client.botlist, fetch, create, update, delete, upvote, downvote
client.bot.sessioncreate
client.datasetlist, fetch, create, update, delete, search
client.dataset.recordlist, export, fetch, create, update, delete
client.dataset.filelist, attach, detach, sync
client.skillsetlist, fetch, create, update, delete
client.skillset.abilitylist, export, fetch, create, update, delete, execute
client.filelist, fetch, create, update, delete, upload, download, sync
client.contactlist, fetch, create, update, delete, ensure
client.contact.conversationlist
client.user, client.user.sessionlist, fetch, create, update, delete; create session
client.platform.modellist

Endpoints without a wrapper yet can be called through the base client with the generated types:

let blueprints: BlueprintListResponse = try await client.fetch( ClientRequest(path: "/api/v1/blueprint/list", query: BlueprintListParams(take: 10)) )

swift

Uploads

let file = try await client.file.create(FileCreateRequest(name: "handbook.pdf")) try await client.file.upload(file.id, data: pdfData, name: "handbook.pdf", type: "application/pdf") try await client.conversation.attachment.upload(conversationId, data: imageData, name: "photo.jpg", type: "image/jpeg")

swift

The API returns a pre-signed upload request and the SDK sends the bytes straight to storage. Attachment uploads also work with a conversation session token.

Error Handling

ErrorWhen
FetchErrorNon-2xx response, with code (e.g. NOT_FOUND), message, status, data.
AuthorizationRequiredErrorA secret or connection must be authorized first; url is where to go.
TimeoutErrorThe request timed out.
CancellationErrorThe task was cancelled.
do { _ = try await client.conversation.fetch("missing") } catch let error as FetchError where error.code == "NOT_FOUND" { print("No such conversation") }

swift

Values the API may extend later, such as message and event types, are open types with static members like .user and .token, so a new value from the server decodes instead of failing.

Examples

The SDK repository includes two examples:

  • CLI chat (examples/cli): creates a conversation and streams replies in the terminal. Runs on macOS and Linux with CHATBOTKIT_API_SECRET=... swift run.
  • SwiftUI chat app (examples/swiftui-chat): a complete iOS and macOS app with a conversation list, streaming chat view, a stop button and file attachments. It logs in with session tokens minted by a small backend; the example README describes the three backend endpoints and includes a reference implementation with the Node SDK.