The one you will see first#
Code -2, authentication failed. Your credentials are missing, wrong, or presented by an app they were not issued to.Check three things, in this order:1.
All credentials are present. On Android, all three meta-data entries sit inside <application>. On iOS, you called configure, or both Info.plist keys are spelled correctly.
2.
Your bundle identifier or application ID matches the app in the dashboard.
3.
You copied the values with no leading or trailing spaces.
Every code#
| Code | Name | Meaning | What to do |
|---|
0 | OK | Success | Nothing |
-1 | Init | The SDK is not started | Call register or configure first |
-2 | Auth | Credentials refused | See above |
-3 | HTTP | The network request failed | Retry. Check the device is online |
-4 | Crypto | An encryption step failed | Report it to us. This is a bug |
-5 | Parse | The server sent something unreadable | Retry. Report it if it repeats |
-6 | IO | A file or keychain read failed | On iOS, check the App Group |
-7 | Expired | The session expired | The SDK retries by itself |
-8 | Not found | The number is not in the data | Nothing. This is normal |
-9 | Busy | Another lookup for that number is running | Treat as unknown |
-8 and -9 are not failures. Both mean "no answer for this number". Show your fallback text.Android#
lookupLabel returns null for both "not a business" and a failed lookup. It never throws for a lookup failure.Use lookupLabelCode when the difference matters:spamCheckCode returns 1 for spam, 0 for clean, and a negative code for a failure. isSpam collapses every failure to false, so it fails open.A lookup before register throws IllegalStateException with the message CallerAPI not initialised - call register() first. That is a programming mistake, not a runtime condition, so do not catch it. Fix the startup order.Init failures do not throw. register logs the failure and the SDK stays off. Filter Logcat for CallerAPI and look for native init failed.iOS#
Both lookup functions throw CallerAPIError:lookupLabel returns nil rather than throwing for code -8, so a number that is not a business is not an error.CallerAPIError has localizedDescription, so you can log it without a switch.Flutter#
Failures arrive as PlatformException. The numeric code is not exposed, so treat any throw as "no answer":React Native#
The promise rejects. The numeric code is not exposed:let name: string;
try {
name = (await CallerAPI.lookupLabel(phone)) ?? 'Unknown';
} catch (e) {
console.warn('CallerAPI lookup failed', e);
name = 'Unknown';
}
Quota and rate errors#
These come from the server, not from the codes above.| Response | Meaning | What to do |
|---|
402 with sandbox_limit_reached | 200 devices this month, on a sandbox app | Contact us to go live |
402 with mau_cap_reached | Your agreed device cap is reached | Contact us to raise it |
429 | Too many requests from this device | Wait. Retry-After says how long |
Devices already counted this month keep working past a cap. Only new devices are refused, so the problem shows up as new installs failing while existing users are fine.Always fail open#
Never block a call or hide a contact because a lookup failed. A missed spam call annoys a user. A blocked real call loses you one.Every default in the SDK follows this rule. isSpam returns false on failure, and the Android call screening path lets an unknown number ring.Modified at 2026-07-29 23:18:34