Voqal iOS SDK 1.2.2
The voice-first, render-spec SDK — drop in the assistant, point it at your backend, and ship a themed voice + chat experience.
Looking for the legacy SDK docs?Integration
- In Xcode, choose File → Add Package Dependencies…
- Enter the package URL:
https://github.com/VoqalAI/voqal-iosand add the VoqalSDK library. - Set the dependency rule to Up to Next Major from 1.2.2.
- Minimum deployment target: iOS 16. Add
NSMicrophoneUsageDescriptionandNSFaceIDUsageDescriptionto your Info.plist (mic for voice, Face ID for high-risk confirmations).
Setup
Step 1: Provide credentials via a delegate
Conform to VocalButtonDelegate. The SDK reads the auth token live on every request, so always return a currently-valid token — refresh it before it expires.
import VoqalSDK
extension ViewController: VocalButtonDelegate {
// Your end-user's auth token for the MCP backend (kept fresh by your app).
func getToken() -> String { authStore.currentToken }
// Optional JSON: country, user id, etc. Drives region + personalization.
func getMetaData() -> String? {
#"{"country_code":"EGY","user_id":"285"}"#
}
// The view controller the assistant is presented from.
func getViewController() -> UIViewController { self }
func voqalButton(didUploadRecording result: String) {} // recording lifecycle
func voqalButton(didFailWith error: Error) {}
}Step 2: Configure & register the SDK
Build a VoqalSDKConfiguration, set your API key and theme, then register it once at launch.
import VoqalSDK
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [...]?) -> Bool {
var config = VoqalSDKConfiguration(requestId: "prod-yourapp")
config.apiKey = "pk_live_…" // your Voqal API key (required)
config.theme = VoqalTheme(accent: "#2d5bff", accent2: "#5b8dff",
appearance: .auto)
config.home = VoqalHome(
userName: "Nour",
pinnedCTAs: ["What's my balance?", "Create a payment link"])
VoqalSDKManager.shared.setup(configuration: config)
// Optional but recommended: warm the engine in the background so the
// assistant answers instantly the first time it opens. Pass any object
// conforming to VocalButtonDelegate (see the next step).
VoqalSDKManager.shared.prewarm(delegate: voqalDelegate)
return true
}prod- → production, stg- → staging.Presenting the assistant
Two ways to open it — use the built-in orb button, or present it yourself from any of your own buttons.
Option A — the Voqal orb button
let voqal = VoqalButton()
voqal.delegate = self // your VocalButtonDelegate
view.addSubview(voqal) // tapping it opens the assistantOption B — present from any button
@objc func openAssistant() {
VoqalSDKManager.shared.presentChat(
from: self, // any UIViewController
delegate: self, // your VocalButtonDelegate
animated: true)
}Complete example
Everything together — register the SDK at launch, present it from your own button, and supply credentials live.
import UIKit
import VoqalSDK
// 1) Register the SDK once at launch.
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
// Retained so prewarm's background task always has live credentials.
let voqalDelegate = VoqalCredentialsDelegate()
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
var config = VoqalSDKConfiguration(requestId: "prod-yourapp") // "prod-" / "stg-"
config.apiKey = "pk_live_…" // your Voqal API key
config.theme = VoqalTheme(accent: "#2d5bff", accent2: "#5b8dff",
appearance: .auto)
config.home = VoqalHome(userName: "Nour",
pinnedCTAs: ["What's my balance?", "Create a payment link"])
VoqalSDKManager.shared.setup(configuration: config)
VoqalSDKManager.shared.prewarm(delegate: voqalDelegate) // warm the engine at launch
#if DEBUG
VoqalSDKManager.shared.addLogSink(VoqalConsoleLogSink()) // log every event/error
#endif
return true
}
}
// 2) Open the assistant from any of your own buttons.
final class HomeViewController: UIViewController {
let voqal = VoqalCredentialsDelegate()
@objc func openAssistant() {
VoqalSDKManager.shared.presentChat(from: self, delegate: voqal, animated: true)
}
}
// 3) Supply credentials live — the SDK reads these on every request.
final class VoqalCredentialsDelegate: NSObject, VocalButtonDelegate {
func getToken() -> String { TokenStore.shared.current } // keep this token fresh
func getMetaData() -> String? { #"{"country_code":"EGY","user_id":"285"}"# }
func getViewController() -> UIViewController {
UIApplication.shared.connectedScenes
.compactMap { ($0 as? UIWindowScene)?.keyWindow?.rootViewController }
.first ?? UIViewController()
}
func voqalButton(didUploadRecording result: String) {} // recording lifecycle
func voqalButton(didFailWith error: Error) {}
}Theming
One VoqalTheme drives the whole experience. Surfaces, hairlines and text tiers are derived automatically so it looks native in light or dark.
config.theme = VoqalTheme(
accent: "#2d5bff", // your brand color (hex)
accent2: "#5b8dff", // optional gradient pair
appearance: .auto, // .light · .dark · .auto (follows the phone)
fontName: nil, // optional custom display font
radius: 20) // base corner radius for cards & the sheetCustomization
- Home screen —
VoqalHome(userName:pinnedCTAs:showAgentGlance:): the greeting name, the "Try saying" suggestions, and whether to show the live data glance. - Header title —
config.strings.chatHeaderTitle(defaults to "Voqal"). - Icons —
config.icons.chatHeaderIcon(header mark) andconfig.icons.voqalButtonIcon(the launcher). Leave unset for the accent orb. - Fast first turn — call
VoqalSDKManager.shared.prewarm(delegate:)right aftersetup: it opens the engine connection in the background so the assistant is instant when the user opens it. - Conversation memory —
config.conversationTimeout(default 2h): how long a conversation resumes after the sheet is closed & reopened.
Configuration reference
| Property | Type | Default | Description |
|---|---|---|---|
requestId | String | required | Environment routing — prod- or stg- prefix. |
apiKey | String | required | Your Voqal API key (pk_live_…), sent as X-Voqal-Key. |
theme | VoqalTheme | default | accent, accent2, appearance (.light/.dark/.auto), fontName, radius. |
home | VoqalHome | empty | userName, pinnedCTAs, showAgentGlance. |
strings | …StringsConfiguration | "Voqal" | chatHeaderTitle — the assistant's name in the header. |
icons | …IconConfiguration | accent orb | chatHeaderIcon, voqalButtonIcon. |
conversationTimeout | TimeInterval | 7200 | How long a conversation resumes after close/reopen (seconds). |
agentURL | URL? | baked in | Override the engine endpoint (rarely needed). |
API key & security
- Every app needs a Voqal API key (
pk_live_…), set onconfig.apiKey. We issue one per integrator — requests without a valid key are rejected. - Each session establishes a device key in the Secure Enclave and signs every request (proof-of-possession), so a leaked session token is useless without the device.
- Money-movement actions are never executed inline — they surface a confirm card first. High-risk actions (e.g. instant settlement) additionally require Face ID; lower-risk ones (e.g. creating a payment link) are a single tap.
- Session tokens refresh automatically and silently — no error is shown to the user.
Diagnostics
- VoqalSDK includes built-in crash and error reporting so issues are detected and resolved quickly. It works automatically — no setup required.
- It is privacy-preserving: auth tokens and personal data are never sent. You may wish to note the presence of in-app diagnostics in your privacy policy.
Need an API key?
We issue a Voqal API key per integrator. Reach out and we'll get you set up, or check the SDK repository for the latest release.