Voqal iOS SDK 1.3.0
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.3.0.
- 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 sheetPresentation style
Choose how the assistant appears. The default .sheet slides up and is swipe-to-dismiss; .fullScreen takes the whole screen edge-to-edge and dismisses via the close button. This is a setup-time setting.
config.presentationStyle = .fullScreen // default: .sheetHeader branding
Replace the default "Voqal" title and mark with your own. Set the header title on config.strings and the icon on config.icons. Leave them unset to fall back to the default Voqal title and mark.
config.strings.chatHeaderTitle = "Rabbit"
config.icons.chatHeaderIcon = UIImage(named: "RabbitLogo")Customization
- Home screen —
VoqalHome(userName:pinnedCTAs:showAgentGlance:): the greeting name, the "Try saying" suggestions, and whether to show the live data glance. - Presentation —
config.presentationStyle(.sheet/.fullScreen). - 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. |
presentationStyle | PresentationStyle | .sheet | .sheet (slide-up) or .fullScreen (edge-to-edge). |
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.