Flutter SDK
Send and verify SMS OTP codes in Flutter iOS & Android apps
Installation
dependencies:
baxcloud_verify_sdk: ^1.2.0flutter pub getPublished on pub.dev. The SDK connects to BaxCloud automatically — only projectId and apiKey are required.
Quick Start
1import 'package:baxcloud_verify_sdk/baxcloud_verify_sdk.dart';
2
3final verify = BaxCloudVerifyClient(
4 config: BaxCloudVerifyConfig(
5 projectId: 'your-project-id',
6 apiKey: 'your-baxverify-api-key',
7 debug: true,
8 ),
9);
10
11// Send OTP
12final sent = await verify.sendOtp(
13 SendOtpOptions(
14 phone: '+14155552671',
15 purpose: BaxVerifyOtpPurpose.login,
16 ),
17);
18
19// Verify OTP — returns accessToken
20final result = await verify.verifyOtp(
21 VerifyOtpOptions(phone: '+14155552671', code: '123456'),
22);
23
24// Send proof to your backend or auth adapter
25final proof = result.externalAuth; // { id: phone, token: accessToken }Configuration
| Option | Required | Description |
|---|---|---|
| projectId | Yes | BaxCloud project ID |
| apiKey | Yes | API key with BaxVerify enabled |
| debug | No | Log SDK activity |
Production tip: proxy sendOtp / verifyOtp through your backend when possible so the API key is not embedded in the app. The accessToken flow works either way.
Verification access token
After verifyOtp, use result.accessToken with any backend. Validate on your server with @baxcloud/baxverify or the REST validate-token endpoint — not with a secret key in the mobile app.
1// Third-party auth envelope (Parse, custom adapters)
2final auth = result.externalAuth;
3// { 'id': '+14155552671', 'token': 'eyJhbG...' }1// Exchange proof on your backend
2final result = await verify.verifyOtp(...);
3await http.post(
4 Uri.parse('https://your-api.com/auth/phone-login'),
5 headers: {'Content-Type': 'application/json'},
6 body: jsonEncode({
7 'phone': result.phone,
8 'baxverifyToken': result.accessToken,
9 }),
10);Parse Server login
BaxVerify proves phone ownership; Parse Server creates the user session. Install @baxcloud/parse-server-baxverify on Parse Server (setup guide), then log in from Flutter:
dependencies:
baxcloud_verify_sdk: ^1.2.0
parse_server_sdk: ^6.0.01import 'package:parse_server_sdk/parse_server_sdk.dart';
2import 'package:baxcloud_verify_sdk/baxcloud_verify_sdk.dart';
3
4await Parse().initialize(
5 'YOUR_PARSE_APP_ID',
6 'https://your-parse-server.com/parse',
7 clientKey: 'YOUR_PARSE_CLIENT_KEY',
8);
9
10// 1. Send + verify OTP with BaxVerify
11final result = await verify.verifyOtp(
12 VerifyOtpOptions(phone: '+14155552671', code: userEnteredCode),
13);
14
15// 2. Log in to Parse with authData { id, token }
16final response = await ParseUser.logInWith(
17 'baxverify',
18 result.externalAuth!,
19);
20
21if (response.success) {
22 final user = response.result as ParseUser;
23 // user.sessionToken is your Parse session
24}- Flutter:
sendOtp→ user enters SMS code - Flutter:
verifyOtp→accessToken - Flutter:
ParseUser.logInWith('baxverify', externalAuth) - Parse Server:
@baxcloud/parse-server-baxverifyvalidates the token
Example in the package: example/parse_phone_login.dart on pub.dev.
API Methods
| Method | Description |
|---|---|
| sendOtp | Send SMS verification code |
| verifyOtp | Verify code; returns accessToken |
| validateVerificationToken | Server-side token validation |
| getStats | Sent / verified / failed counts |
| listLogs | Paginated delivery logs |
Error codes
Failed BaxVerify API calls return a structured JSON envelope. Use error.code for programmatic handling and error.details.helpUrl to link users to the right dashboard page.
{
"success": false,
"error": {
"code": "BAXVERIFY_FEATURE_DISABLED",
"message": "BaxVerify is not enabled for this project. Enable it under Project → Features.",
"details": {
"projectId": "your-project-id",
"helpUrl": "https://baxcloud.tech/dashboard/projects/your-project-id?tab=features",
"docsUrl": "https://baxcloud.tech/docs/baxverify"
}
},
"timestamp": "2026-06-06T12:00:00.000Z",
"path": "/v1/auth/sms/send"
}| Code | HTTP | Message | What to do |
|---|---|---|---|
| BAXVERIFY_FEATURE_DISABLED | 403 | BaxVerify is not enabled for this project. | Enable BaxVerify under Project → Features (details.helpUrl). |
| BAXVERIFY_PLAN_NOT_INCLUDED | 403 | Your plan does not include BaxVerify. | Upgrade your subscription (details.helpUrl → Billing). |
| BAXVERIFY_API_KEY_SCOPE | 403 | API key lacks BaxVerify scope. | Create or edit an API key with BaxVerify enabled. |
| BAXVERIFY_SENDER_NOT_CONFIGURED | 400 | No SMS sender configured. | Rent a phone number and/or register a Sender ID in BaxVerify Setup (details.helpUrl). |
| BAXVERIFY_INSUFFICIENT_CREDITS | 400 | Insufficient credits for SMS delivery. | Add credits in Billing before sending (details.helpUrl). |
| BAXVERIFY_VERIFY_FEE_CREDITS | 400 | Insufficient credits for the verification fee. | Add credits in Billing (details.helpUrl). |
| BAXVERIFY_NO_SUBSCRIPTION | 400 | No active subscription for this project. | Subscribe or restore billing for the project. |
| BAXVERIFY_RATE_LIMIT | 429 | Rate limit exceeded. | Wait before sending or verifying another code. |
| BAXVERIFY_OTP_EXPIRED | 400 | Code expired or not found. | Call send again to request a new code. |
| BAXVERIFY_OTP_INVALID | 400 | Invalid verification code. | Ask the user to re-enter the code from SMS. |
| BAXVERIFY_OTP_MAX_ATTEMPTS | 429 | Too many failed attempts. | Request a new code via send. |
| BAXVERIFY_INVALID_PHONE | 400 | Phone number is not valid. | Use full international format with country code (e.g. +14155552671). |
| BAXVERIFY_SMS_SEND_FAILED | 400 | Failed to send SMS. | Check sender setup, destination number, and provider status. |
| BAXVERIFY_TOKEN_INVALID | 401 | Verification token is invalid or expired. | User must verify OTP again to obtain a new accessToken. |
| BAXVERIFY_TOKEN_CONSUMED | 401 | Verification token already used. | Tokens are single-use when consume: true — verify OTP again. |
| BAXVERIFY_PROJECT_INACTIVE | 403 | Project is not active. | Reactivate the project in the dashboard. |
| BAXVERIFY_PROJECT_HEADER_REQUIRED | 400 | X-Project-Id header is required. | Send X-Project-Id with every request. |
| BAXVERIFY_API_KEY_PROJECT_MISMATCH | 403 | API key does not belong to this project. | Use an API key created for the same project as X-Project-Id. |
1try {
2 await verify.sendOtp(SendOtpOptions(phone: '+14155552671', purpose: 'LOGIN'));
3} on BaxVerifyException catch (e) {
4 switch (e.code) {
5 case 'BAXVERIFY_FEATURE_DISABLED':
6 // e.helpUrl → enable BaxVerify in dashboard
7 break;
8 case 'BAXVERIFY_SENDER_NOT_CONFIGURED':
9 // e.helpUrl → BaxVerify Setup
10 break;
11 case 'BAXVERIFY_INSUFFICIENT_CREDITS':
12 // e.helpUrl → Billing
13 break;
14 default:
15 print('${e.statusCode} ${e.code}: ${e.message}');
16 }
17}