BaxCloud Verify SDK for Flutter

SMS OTP verification for iOS and Android apps via BaxVerify.

Installation

dependencies:
  baxcloud_verify_sdk: ^1.2.0
flutter pub get

Quick Start

import 'package:baxcloud_verify_sdk/baxcloud_verify_sdk.dart';

final verify = BaxCloudVerifyClient(
  config: BaxCloudVerifyConfig(
    projectId: 'your-project-id',
    apiKey: 'your-baxverify-api-key',
    debug: true,
  ),
);

// Send OTP
final sent = await verify.sendOtp(
  SendOtpOptions(phone: '+14155552671', purpose: BaxVerifyOtpPurpose.login),
);

// Verify OTP — returns a short-lived accessToken
final result = await verify.verifyOtp(
  VerifyOtpOptions(phone: '+14155552671', code: '123456'),
);
print('Token expires in ${result.expiresIn}s');

Verification access token

After a successful verifyOtp, BaxVerify returns a short-lived JWT (accessToken) that proves the phone number was verified. Use it with any backend or auth system:

  1. Your API — client sends accessToken; your server calls POST /auth/sms/validate-token and issues your own session/JWT.
  2. Third-party auth — pass result.externalAuth ({ id: phone, token }) to providers that support custom auth adapters (e.g. Parse Server logInWith).
  3. Server-side SDK — call validateVerificationToken() from a trusted backend (not from the mobile app with a secret key).

Tokens are single-use by default when validated with consume: true.

Example: exchange token on your backend

// Mobile app — after verifyOtp
final result = await verify.verifyOtp(...);
await http.post(
  Uri.parse('https://your-api.com/auth/phone-login'),
  headers: {'Content-Type': 'application/json'},
  body: jsonEncode({
    'phone': result.phone,
    'baxverifyToken': result.accessToken,
  }),
);
// Your backend
const res = await fetch('https://api.baxcloud.tech/v1/auth/sms/validate-token', {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${BAXCLOUD_API_KEY}`,
    'X-Project-Id': PROJECT_ID,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({ token: baxverifyToken, consume: true }),
});
const { data } = await res.json();
// data.phone is verified — issue your session JWT, create user, etc.

Parse Server phone login

BaxVerify proves the phone; Parse Server issues the user session. Your Parse Server validates the BaxVerify JWT — the BaxCloud API key stays on the server only.

Flutter client

dependencies:
  baxcloud_verify_sdk: ^1.2.0
  parse_server_sdk: ^6.0.0
import 'package:parse_server_sdk/parse_server_sdk.dart';
import 'package:baxcloud_verify_sdk/baxcloud_verify_sdk.dart';

await Parse().initialize(
  'YOUR_PARSE_APP_ID',
  'https://your-parse-server.com/parse',
  clientKey: 'YOUR_PARSE_CLIENT_KEY',
);

// After sendOtp + user enters SMS code:
final result = await verify.verifyOtp(
  VerifyOtpOptions(phone: '+14155552671', code: code),
);

final authData = result.externalAuth!; // { id: phone, token: accessToken }

final response = await ParseUser.logInWith('baxverify', authData);
if (response.success) {
  final user = response.result as ParseUser;
  print(user.sessionToken);
}

Full example: example/parse_phone_login.dart

Parse Server (Node.js)

npm install @baxcloud/parse-server-baxverify
auth: {
  baxverify: { module: '@baxcloud/parse-server-baxverify' },
},

Set BAXCLOUD_PROJECT_ID and BAXCLOUD_API_KEY on Parse Server. See Parse Server docs.

Prerequisites

  1. Enable BaxVerify on your BaxCloud project (Dashboard → BaxVerify).
  2. Create an API key with the BaxVerify scope enabled.
  3. Complete BaxVerify setup: rent a phone number and/or register a Sender ID.

Production tip: Prefer proxying send/verify through your own backend so the BaxCloud API key is not embedded in the mobile app. The accessToken flow is designed for secure session exchange either way.

API Reference

Method Description
sendOtp(SendOtpOptions) Send SMS verification code
verifyOtp(VerifyOtpOptions) Verify code; returns accessToken
validateVerificationToken(...) Server-side token validation
getStats({days}) Usage stats (sent, verified, failed)
listLogs({phone, status, page}) Paginated delivery logs

Authentication

All requests use:

Authorization: Bearer <api_key>
X-Project-Id: <project_id>

Error Handling

API errors include a stable code and optional details.helpUrl. BaxVerifyException exposes code, message, and helpUrl:

try {
  await verify.sendOtp(SendOtpOptions(phone: '+14155552671', purpose: 'LOGIN'));
} on BaxVerifyException catch (e) {
  switch (e.code) {
    case 'BAXVERIFY_FEATURE_DISABLED':
      // e.helpUrl → enable BaxVerify under Project → Features
      break;
    case 'BAXVERIFY_SENDER_NOT_CONFIGURED':
      // e.helpUrl → BaxVerify Setup
      break;
    case 'BAXVERIFY_INSUFFICIENT_CREDITS':
      // e.helpUrl → Billing
      break;
    default:
      print('${e.statusCode} ${e.code}: ${e.message}');
  }
}

Full list: Error codes

Documentation

License

See LICENSE.