Connect, record, sync, and transcribe with Plaud devices.
Quick Start β’ Template App β’ SDK Guide β’ Transcription API
Plaud SDK enables B2B partners to integrate Plaud recording devices into their own apps. This repository includes:
sdk/β Precompiled SDK binaries (iOS.framework+ Android.aar)plaud-template-app/β A complete iOS reference app demonstrating every SDK feature
Coming soon: Android Template App and demo video walkthrough.
plaud-sdk-public/
βββ sdk/
β βββ ios/ # iOS SDK frameworks
β β βββ PlaudBleSDK.framework # BLE communication
β β βββ PlaudDeviceBasicSDK.framework # Core device management
β β βββ PlaudDeviceBasicSDK.bundle # SDK resources
β β βββ PlaudWiFiSDK.framework # WiFi fast transfer
β βββ android/ # Android SDK
β βββ plaud-sdk.aar # Android AAR package
βββ plaud-template-app/
β βββ ios/ # iOS Template App
β βββ project.yml # Xcodegen config
β βββ PartnerConfig.xcconfig # SDK credentials (edit this!)
β βββ PlaudTemplateApp/ # Source code
βββ LICENSE
βββ README.md
- Xcode 16.0+ (SDK built with Swift 6.0.3, compatible with Xcode 16+)
- iOS 14.0+ deployment target
- Xcodegen (
brew install xcodegen) - A Plaud partner account with User Access Token
Edit plaud-template-app/ios/PartnerConfig.xcconfig:
# Required for SDK initialization
USER_ACCESS_TOKEN = your-jwt-token
# Required for Transcription API (optional, not needed for device features)
PLAUD_CLIENT_ID = your-client-id
PLAUD_API_KEY = your-api-key
Tip: Create
plaud-template-app/ios/PartnerConfig.local.xcconfigwith your real credentials β it's gitignored and will override the placeholder values.Where to get these:
USER_ACCESS_TOKEN: Your backend callsPOST /open/partner/users/access-tokento obtain this per-user JWT.PLAUD_CLIENT_ID+PLAUD_API_KEY: Create in the Plaud Developer Portal. See the QUICKSTART guide for details.
Edit plaud-template-app/ios/project.yml:
- Change
bundleIdPrefix: com.plaudto your own Bundle ID prefix (e.g.,com.yourcompany) - Xcode will auto-assign your Development Team on first build
cd plaud-template-app/ios
xcodegen generateOpen plaud-template-app/ios/PlaudTemplateApp.xcodeproj in Xcode, select your physical device, and run.
Note: SDK frameworks are compiled for
arm64(physical devices only). Simulator is not supported.
The Template App is a fully functional iOS app demonstrating every SDK capability. Use it as a reference for your own integration.
| Feature | Description |
|---|---|
| π Device Connection | BLE scanning, pairing, and auto-reconnect |
| π± Multi-Device | Pair multiple devices, switch between them |
| ποΈ Recording | Real-time recording with live PCM waveform |
| π₯ File Sync | BLE sync with auto-download on connect |
| β‘ WiFi Fast Transfer | ~10x faster than BLE |
| π Firmware Update | OTA upgrade with progress UI |
| π Transcription | Speech-to-text via S3 upload + API |
| π Audio Playback | MP3 playback with floating player |
| Layer | Technology |
|---|---|
| Language | Swift |
| UI | UIKit (programmatic, no Storyboard) |
| Pattern | MVVM + Combine |
| Build | Xcodegen (project.yml β .xcodeproj) |
| Min Target | iOS 14.0 |
PlaudTemplateApp/
βββ App/ # SceneDelegate (launch routing)
βββ Common/ # PlaudTheme, PlaudToggle, Extensions
βββ Managers/
β βββ DeviceManager # SDK wrapper: scan/connect/OTA/multi-device
β βββ RecordingManager # Recording state + PCM waveform
β βββ SyncManager # File sync (BLE + WiFi fast transfer)
β βββ TranscriptionManager # S3 upload + transcription polling
β βββ PlaudAPIService # HTTP API client (upload, transcription)
β βββ Mock/ # Mock implementations for UI development
βββ Models/ # PlaudDevice, RecordingFile, SyncState, etc.
βββ Storage/ # RecordingStore (local persistence)
βββ UI/
βββ Onboarding/ # Welcome β Scanning β Connect β Success
βββ Main/ # MainTabBarController (floating capsule tab bar)
βββ Home/ # DeviceCard + RecordingTrigger + RecentFiles
βββ Recording/ # Full-screen recording with waveform
βββ Files/ # File list grouped by date
βββ FileDetail/ # Transcript + audio player
βββ Settings/ # Firmware update + Sign out
Launch Routing
- Has paired devices + userId β
MainTabBarController(auto-reconnect in background) - No paired devices β
WelcomeViewController
Auto-Reconnect
sceneDidBecomeActivetriggers scan after 2-second delay (BLE power-on time)bleScanResultmatchesactiveDeviceSNβ auto-connectstartAutoReconnect: 30-second interval timer, max 10 attempts
Multi-Device
RecordingStore.pairedDeviceSNs: array of paired device SNsRecordingStore.activeDeviceSN: currently active device- BLE only supports one connection at a time; switching disconnects current, scans for target
- SDK handles per-device sn-sign caching internally
Recording & Waveform
syncFile(sessionId:start:end:)enables PCM decode streamblePcmDatadelivers decoded PCM (640 bytes, 16kHz mono)JXRecordVolumer.shared.averageVolume(pcmData)β dB volume- 100ms timer for smooth waveform rendering (decoupled from BLE jitter)
File Sync
- On connect:
getFileList()βexportAudio(format: .mp3)βdeleteFile() - MP3 format: playable by AVAudioPlayer + accepted by transcription API upload
- Files belong to the phone after sync; device files are always unsynced
Firmware Update
checkFirmwareUpdate()on device connectFirmwareUpdateSheetViewController: bottom sheet with segmented progress barisOTAInProgressflag prevents auto-reconnect interference during OTA- Sheet waits for device restart + reconnect before dismissing
Transcription
TranscriptionManager: upload β submit β poll workflow- S3 multipart upload:
generatePresignedURLsβ PUT parts βcompleteUpload - Submit:
POST /open/partner/ai/transcriptions/ - Poll every 3 seconds until
task_status == "COMPLETED"
| SN Prefix | Type | Device |
|---|---|---|
| 881 | notepro | Plaud NotePro |
| 883 | notepins | Plaud NotePinS |
| xcconfig Key | Info.plist Key | Usage |
|---|---|---|
USER_ACCESS_TOKEN |
UserAccessToken |
SDK initialization (required) |
PLAUD_CLIENT_ID |
PlaudClientId |
Transcription API (X-Client-Id header) |
PLAUD_API_KEY |
PlaudApiKey |
Transcription API (X-Client-Api-Key header) |
If you're building your own app from scratch (not using the Template App), follow this guide.
| Framework | Action |
|---|---|
PlaudBleSDK.framework |
Embed & Sign |
PlaudWiFiSDK.framework |
Embed & Sign |
PlaudDeviceBasicSDK.framework |
Embed & Sign |
PlaudDeviceBasicSDK.bundle |
Copy Bundle Resources |
import PlaudDeviceBasicSDK
PlaudDeviceAgent.shared.initSDK(
userAccessToken: "your-jwt-token",
customDomain: "platform-us.plaud.ai" // domain only, no https://
)| Parameter | Required | Description |
|---|---|---|
userAccessToken |
Yes | JWT token for device authentication. Handshake token is auto-parsed from the sub field. |
customDomain |
Yes | Server domain without https:// prefix. |
PlaudDeviceAgent.shared.setUserAccessToken(newToken)PlaudDeviceAgent.shared.delegate = self
PlaudDeviceAgent.shared.startScan()
PlaudDeviceAgent.shared.connectBleDevice(bleDevice: device)| Callback | Description |
|---|---|
bleScanResult(bleDevices:) |
Scan results updated |
bleConnectState(state:) |
1=connected, 0=disconnected |
bleBind(sn:status:...) |
Device bound successfully |
blePenState(state:...) |
Handshake complete |
PlaudDeviceAgent.shared.getFileList(startSessionId: 0)
PlaudDeviceAgent.shared.exportAudio(
sessionId: sessionId,
outputDir: outputDir,
format: .mp3, // MP3: playable + uploadable for transcription
channels: 1,
callback: self
)
PlaudDeviceAgent.shared.deleteFile(sessionId: sessionId)~10x faster than BLE. Requires Hotspot Configuration entitlement.
PlaudDeviceAgent.shared.setDeviceWiFi(open: true)
// In bleWiFiOpen callback:
PlaudWiFiAgent.shared.bleDevice = BleAgent.shared.bleDevice
PlaudWiFiAgent.shared.connectWifi(ssid, password, 60)
// After wifiHandshake(status: 0):
PlaudWiFiAgent.shared.exportAudioViaWiFi(...)SDK handles the full flow: version check β download β verify β push β restart β reconnect.
// Check for update
PlaudDeviceAgent.shared.checkFirmwareUpdate { result in
guard result.hasUpdate else { return }
}
// One-call update
PlaudDeviceAgent.shared.startFirmwareUpdate(
progress: { phase, percentage in
// .downloading / .installing / .restarting / .complete
},
completion: { result in
print(result.success ? "Updated to \(result.version)" : "Failed: \(result.errorMessage ?? "")")
}
)These APIs are called directly by the application, not through the SDK.
Uses X-Client-Id + X-Client-Api-Key headers. Configure PLAUD_CLIENT_ID and PLAUD_API_KEY in PartnerConfig.xcconfig. These are separate from the USER_ACCESS_TOKEN used for SDK initialization.
API keys can be created in the Plaud Developer Portal under your application's API Keys panel.
1. Upload audio β generate-presigned-urls β PUT parts β complete-upload
2. Submit β POST /open/partner/ai/transcriptions/
3. Poll β GET /open/partner/ai/transcriptions/{id}
Base URL: https://platform-us.plaud.ai/developer/api
| Endpoint | Method | Auth | Description |
|---|---|---|---|
/open/partner/files/upload/generate-presigned-urls |
POST | Bearer user token | Get S3 upload URLs |
/open/partner/files/upload/complete-upload |
POST | Bearer user token | Complete multipart upload |
/open/partner/ai/transcriptions/ |
POST | X-Client-Id + X-Client-Api-Key | Submit transcription |
/open/partner/ai/transcriptions/{id} |
GET | X-Client-Id + X-Client-Api-Key | Get transcription result |
Apache License 2.0 β see LICENSE for details.
The Plaud SDK binaries in the sdk/ directory (iOS frameworks and Android AAR) are proprietary and distributed under a separate license.