Amba

Troubleshooting

Common Amba errors, what they mean, and the fix.

A short, honest index of the errors you're most likely to hit, with the fix. Every error response from the Amba API follows the shape { "error": { "code": "...", "message": "...", "details"?: ... } } — switch on code, not message.

Auth

401 INVALID_CREDENTIALS (developer login)

Email or password doesn't match. Amba doesn't disambiguate wrong email vs wrong password for security. Reset via support; self-serve password reset is on the roadmap.

401 INVALID_CREDENTIALS (SDK loginWithEmail)

End-user flow — wrong password, or the email doesn't exist. If your signup flow is failing silently, check err.code on the server side (USER_EXISTS, WEAK_PASSWORD, INVALID_EMAIL).

401 INVALID_TOKEN (Apple / Google sign-in)

The Apple or Google identity token failed server-side JWKS verification. Most common causes:

  • The native flow returned an expired token (re-run the flow).
  • The Apple bundle id / Google client id configured on the server doesn't match the app.

401 on Admin API calls

Missing or expired developer bearer token. Refresh via POST /auth/developer/refresh; the SDK auto-rotates, but if you're calling the API manually, check the TTL. Refresh tokens live 30 days.

429 RATE_LIMITED

Developer auth is rate-limited per IP: 5/min and 50/day for signup, 10/min and 100/day for login, 30/min for refresh. Back off and retry.

Webhooks

401 INVALID_SIGNATURE

The signature header failed timingSafeEqual. Checklist:

  • RevenueCat: the Authorization: Bearer <secret> value must match project_integrations.config.webhook_secret byte-for-byte. No extra whitespace.
  • Superwall: the x-superwall-signature header must be the hex HMAC-SHA256 of the raw body using the configured secret. If your proxy re-serializes JSON, the digest changes and verification fails.

404 NOT_CONFIGURED

No active project_integrations row for the provider. Run POST /admin/integrations (or the MCP equivalent) to configure RevenueCat / Superwall with a webhook_secret.

400 MISSING_PROJECT

The webhook URL is missing the ?project_id=proj_xxx query parameter. Copy the webhook_url returned by POST /admin/integrations exactly — don't hand-roll the URL.

500 WEBHOOK_PROCESSING_FAILED (RevenueCat)

Background processing couldn't accept the event. Amba returns 500 deliberately so RevenueCat retries (it will not retry on a 200). Transient failures auto-recover; if it persists, contact support.

Push

404 NO_ACTIVE_TOKEN

You called POST /admin/push/test with app_user_id but the user has no active push_tokens row. Causes:

  • The app never registered a token (simulator, or permission denied).
  • The user's previous token got marked is_active = false after a send-side invalidToken.

Register a fresh token from the device, or pass device_token + provider directly.

502 SEND_FAILED (APNs / FCM)

The provider rejected the send. error.details includes invalid_token, provider, and provider_message_id. Typical reasons:

  • APNs: wrong environment (sandbox vs production) for the bundle / build.
  • FCM: service account missing Firebase Cloud Messaging API permission.
  • Either: the device token is dead. invalid_token: true confirms; deactivate it server-side.

502 CREDENTIAL_LOAD_FAILED

The credentials themselves loaded (or didn't) — infrastructure-level failure. Details include reason:

  • "not configured" → 404 instead (wrong path).
  • Malformed PEM or bad service-account JSON.

Fix the stored config via PATCH /admin/integrations/:provider.

409 ALREADY_SCHEDULED

Trying to /send a campaign that's already scheduled. Let it fire at scheduled_at, or contact support to cancel before it fires.

409 ALREADY_SENT

Campaign is already sending or sent. Create a new campaign for a resend.

400 SCHEDULED_AT_IN_PAST / INVALID_SCHEDULED_AT

scheduled_at either couldn't be parsed as ISO-8601 or is ≤ now(). Pass a future UTC timestamp: "2026-04-20T09:00:00Z".

Remote config

SDK sees stale values

client.config.get() reads from the in-memory cache. init() restores the cache from storage and kicks off a background refresh(). To bypass the TTL:

await client.config.refresh();

ETag-backed 304s are expected — they mean the server confirms the cached payload is still valid.

Config change doesn't roll out

Check that conditions are ordered correctly (first match wins) and that the user actually belongs to the segment you're targeting. Segment membership re-evaluates every 15 minutes — a newly matching user may wait up to 15 minutes before the override applies.

For faster rollouts, use percentage conditions (deterministic, no evaluation latency).

Provisioning

Project stuck in provisioning

When a project is created Amba spins up a dedicated database for it in the background. Status flows are:

  • provisioning — still running. Wait.
  • failed — provisioning errored mid-flight. Contact support.
  • failed_compensated — clean. Safe to retry the original POST /admin/projects.
  • active — all good.

A stuck provisioning for more than a few minutes usually means a transient infra issue and compensation is running.

Tenancy

404 on a client-side call that should work

Your X-Api-Key doesn't resolve to an active projectId, or the project is suspended / archived. Confirm the key is the one the CLI emitted and that the project is active via GET /admin/projects/:id.

Random 500s under load

The first request to a project that's been idle for a while pays a small warm-up cost. Subsequent requests are fast. If you see a single slow first hit after idle, that's expected.

Still stuck?

Collect:

  • Your projectId.
  • The full error response (error.code, error.message, error.details).

Open a GitHub issue or reach out to support with those and we'll root-cause it.