Native SDK Integration
The VeryAI Native SDK adds palm biometric enrollment and verification to your mobile app. Available for iOS (Swift/ObjC), Android (Kotlin/Java), and React Native.
Getting an SDK key
Create a Native SDK app in the Developer Portal to get your sdkKey. Native SDK integrations do not need OAuth client_id or client_secret; those are only for separate browser OAuth flows.
Important: Treat the SDK key as sensitive. If it is extracted from an app, it can be used to call SDK endpoints as that app. It does not grant dashboard access, and keys can be revoked or rotated.
Installation
iOS
Swift Package Manager (recommended):
dependencies: [
.package(url: "https://github.com/veroslabs/very-sdk-ios.git", from: "1.0.47")
] CocoaPods:
pod 'VerySDK', '~> 1.0.47' Then run pod install.
Add camera permission to Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is needed for palm biometric verification.</string> Android
Add the dependency to your app-level build.gradle:
dependencies {
implementation("org.very:sdk:1.0.47")
} The SDK is published on Maven Central.
Add permissions to AndroidManifest.xml:
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" /> React Native
npm install @veryai/react-native-sdk@latest For iOS, install the native dependency:
cd ios && pod install Add camera permission to Info.plist (same as native iOS above).
Published on npm.
Enroll a new user
Pass nil / null / undefined for userId to register a new user.
The SDK opens a consent screen, then guides the user through a palm scan.
iOS (Swift)
import VerySDK
guard VerySDK.isSupported() else {
print("Device not supported")
return
}
let config = VeryConfig(
sdkKey: "your_sdk_key",
userId: nil, // nil = new enrollment
themeMode: "dark"
)
VerySDK.authenticate(
from: self,
config: config,
presentationStyle: .modal
) { result in
if result.isSuccess {
print("User ID: \(result.userId)")
print("Signed token: \(result.signedToken ?? "")")
} else {
print("Error: \(result.errorType) — \(result.errorMessage ?? "")")
}
} Android (Kotlin)
import org.very.sdk.VerySDK
import org.very.sdk.VeryConfig
import org.very.sdk.VeryPresentationStyle
if (!VerySDK.isSupported(context)) {
Log.w("Very", "Device not supported")
return
}
val config = VeryConfig(
sdkKey = "your_sdk_key",
userId = null, // null = new enrollment
themeMode = "dark"
)
VerySDK.authenticate(
context = this,
config = config,
presentationStyle = VeryPresentationStyle.FULL_SCREEN
) { result ->
if (result.isSuccess) {
Log.d("Very", "User ID: ${result.userId}")
Log.d("Very", "Signed token: ${result.signedToken}")
} else {
Log.e("Very", "Error: ${result.errorType} — ${result.errorMessage}")
}
} React Native
import { VerySDK } from '@veryai/react-native-sdk';
const supported = await VerySDK.isSupported();
if (!supported) {
console.warn('Device not supported');
return;
}
const result = await VerySDK.authenticate({
sdkKey: 'your_sdk_key',
userId: undefined, // undefined = new enrollment
themeMode: 'dark',
presentationStyle: 'fullScreen',
});
if (result.isSuccess) {
console.log('User ID:', result.userId);
console.log('Signed token:', result.signedToken);
} else {
console.error('Error:', result.error, result.errorMessage);
} Verify an existing user
Pass the user's ID from a previous enrollment to verify their identity.
iOS (Swift)
let config = VeryConfig(
sdkKey: "your_sdk_key",
userId: "vu-1ed0a927-...", // from previous enrollment
themeMode: "dark"
)
VerySDK.authenticate(from: self, config: config) { result in
if result.isSuccess {
print("Verified user: \(result.userId)")
print("Signed token: \(result.signedToken ?? "")")
}
} Android (Kotlin)
val config = VeryConfig(
sdkKey = "your_sdk_key",
userId = "vu-1ed0a927-...",
themeMode = "dark"
)
VerySDK.authenticate(context = this, config = config) { result ->
if (result.isSuccess) {
Log.d("Very", "Verified user: ${result.userId}")
Log.d("Very", "Signed token: ${result.signedToken}")
}
} React Native
const result = await VerySDK.authenticate({
sdkKey: 'your_sdk_key',
userId: 'vu-1ed0a927-...', // from previous enrollment
themeMode: 'dark',
});
if (result.isSuccess) {
console.log('Verified user:', result.userId);
console.log('Signed token:', result.signedToken);
} Verify the signed token (backend)
When authentication succeeds, the SDK returns userId and signedToken.
Send signedToken to your backend:
POST /api/verify-palm
Content-Type: application/json
{
"signedToken": "eyJhbGciOiJFZERTQSIsImtpZCI6..."
}
Verify the JWT signature with VeryAI's public keys at https://api.very.org/.well-known/jwks.json.
The token is Ed25519-signed. After verification, trust the sub claim as the user's VeryAI ID:
{
"sub": "vu-1ed0a927-a336-45dd-9c73-20092db9ae8d",
"exp": 1761013475,
"iat": 1761009875
} - For enrollment: store the
sub(user ID) - pass it asuserIdfor future verifications - For verification: confirm the
submatches the expected user codeis an SDK status string, not an OAuth authorization code
Important: Do not create an OAuth app for this flow. Native SDK verification uses signedToken and JWKS, not an OAuth token exchange.
Configuration reference
VeryConfig
| Parameter | Type | Default | Description |
|---|---|---|---|
sdkKey | String | required | Your SDK API key |
userId | String? | nil | Nil for enrollment, user ID for verification |
language | String? | device | BCP 47 locale code (e.g. "en", "es", "en-IN", "zh-HK"). Defaults to the device locale; unsupported locales fall back to the default language. |
themeMode | String | "dark" | "dark" or "light" |
baseUrl | String? | production | Override API endpoint (for staging/testing) |
presentationStyle | Enum | modal / fullScreen | iOS: .modal, .push, .embed. Android: FULL_SCREEN, BOTTOM_SHEET. RN: "fullScreen", "bottomSheet". |
livenessMode | Enum | gesture | iOS only: .gesture or .touch |
VeryResult
| Property | Type | Description |
|---|---|---|
isSuccess | Bool | Whether authentication completed successfully |
code | String | SDK status string, not an OAuth authorization code |
userId | String | The user's app-scoped VeryAI ID. The same palm returns the same userId within the same Native SDK app/environment. |
signedToken | String? | Ed25519-signed JWT for backend verification |
error | String? | Error code string |
errorType | VeryErrorType | Typed error (see Error Handling) |
errorMessage | String? | Human-readable error message |
Requirements
iOS
- iOS 16.4+
- Swift 5.0+ / Xcode 16+
- Camera permission
- Physical device for palm capture
Android
- Android 10 (API 29)+
- 2-4GB RAM devices supported
- SDK runtime memory typically under 100MB
- Kotlin 1.8+
- Camera + Internet permissions
React Native
- React Native 0.73+
- iOS and Android requirements above
- Physical device for palm capture
Use isSupported() to check device compatibility at runtime before showing the verification UI.
Current support checks include OS version, camera capability, and SDK runtime compatibility. The SDK does not reject Android devices solely because they have less than 6GB RAM.
React Native troubleshooting
- Use
@veryai/react-native-sdk@latestfor Expo or React Native New Architecture projects. - If iOS fails with missing
VeryConfig,VeryLivenessMode, orisSupported()symbols, upgrade to1.0.47or later and run a freshpod install --repo-update. - If App Store Connect reports unrecognized locale directories such as
enIn.lproj,zhHk.lproj, orzhTw.lproj, upgrade to1.0.47or later. Current builds use BCP 47 names such asen-IN.lproj,zh-HK.lproj, andzh-TW.lproj.
Packages
- iOS: github.com/veroslabs/very-sdk-ios (SPM / CocoaPods)
- Android: org.very:sdk (Maven Central)
- React Native: @veryai/react-native-sdk (npm)