VeryAI Raises $10M Seed Round
Integration Methods /

Native SDK Integration

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 as userId for future verifications
  • For verification: confirm the sub matches the expected user
  • code is 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@latest for Expo or React Native New Architecture projects.
  • If iOS fails with missing VeryConfig, VeryLivenessMode, or isSupported() symbols, upgrade to 1.0.47 or later and run a fresh pod install --repo-update.
  • If App Store Connect reports unrecognized locale directories such as enIn.lproj, zhHk.lproj, or zhTw.lproj, upgrade to 1.0.47 or later. Current builds use BCP 47 names such as en-IN.lproj, zh-HK.lproj, and zh-TW.lproj.

Packages

VeryAI

Get the VeryAI app

Scan the QR code to download the app