Amba

What's New

Release notes for the Amba API, SDKs, and CLI — new features, improvements, and breaking changes with migration notes.

Breaking changes follow semver and ship with migration notes here. Pin your SDK versions and check this page before upgrading.

2026-06-12

New

  • Byte-range requests on the CDN. Asset responses from {projectId}.cdn.amba.host now advertise Accept-Ranges: bytes, and a single Range: bytes=... request on an original asset returns 206 Partial Content with a correct Content-Range — audio and video players can seek into large files without re-downloading the whole object. Suffix (bytes=-500) and open-ended (bytes=1024-) forms are supported; a range starting past the end of the file returns 416 with Content-Range: bytes */<size>; multi-range requests are answered with the full 200 body. Range headers on transformed image URLs are ignored (full response). The new Media Serving & CDN page documents the serving domain, cache lifetimes, image transform parameters, range behavior, and the cache-freshness model.

  • Integrations promote with your project. Promotion bundles now include an integrations section: each active integration's non-secret config (push bundle id, team/key ids, environment) exports with credential material stripped and an explicit credentials: "stripped" marker — bundles stay safe to commit and diff. On import, integrations land in a clearly signalled pending_credentials state (inactive, with per-provider guidance on exactly which call uploads the credentials), or — when the source and target projects belong to the same developer — pass include_integration_credentials: true and the stored credentials are copied directly between the projects' credential stores, entirely server-side, activating push on the target as part of the same import call. No more hand-reconfiguring APNs/FCM after every dev → prod promotion. See the promotion API reference for the new request field, response statuses, and error codes.

  • Generated SDK platform-parity matrix. The SDK platform parity page is now generated directly from the SDK method catalog and the SDK sources — one method-level matrix (136 methods × 34 namespaces × 9 platforms) showing exactly which methods ship on Web, Node, React, React Native, Expo, iOS, Android, Flutter, and Unity. Because the page is generated from the same source of truth the SDKs are built from, it can't drift from what the SDKs actually ship.

Improved

  • Push payload contract, documented field by field. The new payload contract page shows the literal on-device payload for both platforms — the APNs envelope (your data keys top-level alongside aps, alert title/body, mutable-content: 1) and the FCM message (notification title/body, high delivery priority, and the data map where every value arrives as a string — numbers, booleans, and objects are JSON-stringified, so parse them in typed Android handlers). It also states the stability guarantee explicitly: Amba injects nothing into your data — no campaign or segment identifiers (attribution is recorded server-side per delivery) — so tap handlers can rely on your own keys exclusively. No more reverse-engineering test pushes with console logs.
  • INSERT vs PATCH body shapes, stated as a contract. The admin rows reference now documents the deliberate shape split side by side: insert takes a flat column → value map; single-row PATCH canonically takes { "set": { … } } (with the flat body accepted as an alias); bulk PATCH requires the set wrapper because it disambiguates the update payload from the sibling where filter — and a wrong-shape body returns a pointed 400 naming the top-level keys you sent. Also corrected: bulk update rejects an empty where: {} (WHERE_REQUIRED) rather than matching every row, and the admin single-row PATCH's expected compare-and-set is now documented.
  • return=minimal response shapes. The insert reference now shows the id-only response vs the full-row default for both the single insert and rows:batch — pass ?return=minimal (or Prefer: return=minimal) on agent-driven bulk migrations so large JSONB rows don't blow the token budget on echo.
  • Content library delete. The library DELETE reference now spells out the safety contract: deleting a non-empty library is refused with 409 LIBRARY_NOT_EMPTY unless you pass ?cascade=true, which atomically deletes the library and all its items, schedules, and deliveries — irreversibly.
  • Catalog-data docs: collections vs content libraries, search, and array columns. The Content Libraries and Collections pages now open with reciprocal guidance on the global-catalog vs per-user decision — including the trap where admin-seeded rows in a default (read_policy: "owner") collection are invisible to end users, and the read_policy: "public" fix. The collections feature guide and client API reference now fully document typo-tolerant text search (search: { q, columns, fuzzy, threshold } — word-similarity ranking, default threshold 0.3), the like/ilike operators, when to reach for search vs find-nearest, native array column types (text[], integer[], uuid[], …) with the contains / containedBy / overlaps set operators, and arrays-vs-jsonb guidance. The Migrating from Postgres cookbook gained explicit mappings for ILIKE/full-text habits → the search parameter, array columns → native array types (not jsonb), and triggers → event-webhook-driven functions.

2026-06-10

New

  • Filtered, projected, and nested eager-loading on find. An include clause can now carry its own where (filter the related rows), select (project their columns), and include (load relations OF the related rows — novels → chapters → comments, up to 3 levels, one batched query per relation). The included collection's read policy and soft-delete filter still apply independently. Works on the client find (auto-scoped) and the admin row reads. See Eager-loading.
  • having, order_by, and limit on group-by aggregation. Filter the grouped result post-aggregation (having: [{ fn: "count", op: "gte", value: 3 }]), order groups by any group column or select alias, and cap the number of groups — "top 5 statuses by revenue" is now one call on both the client and admin aggregate endpoints.
  • Tail function logs from a request id. amba functions logs <name> --since-request-id r_... starts the log range at the oldest event mentioning that request id and shows everything from there onward — the "show me what happened after this request" debugging flow. Composes with --request-id (filter) and --tail (anchor the backfill, then stream). Also available on the logs API (?since_request_id=) and the amba_functions_get_logs MCP tool.

Improved

  • Monetization & payments docs, zero to paid. New Monetization Quickstart walks the whole journey: declare entitlements / products / offerings in amba.config.json, review the plan (including the human-floor checklist of store-side steps no API performs, with exact console locations), confirm and apply the durable operation, provision the store products, wire the RevenueCat webhook, gate features with Amba.entitlements.has(), and cascade subscribers into segments, push, XP, and currency rewards. The Environment Promotion page now documents the monetization bundle section, the RevenueCat integration page documents the canonical secret_api_key / secret_api_key_write config fields, and the Entitlements page's SDK snippets were corrected to the real method names (entitlements.has() / entitlements.list()).

  • Storage bucket bucket_path field. Bucket admin responses (/admin/projects/:projectId/storage/buckets) now return bucket_path — the URL path segment assets are served under. The old r2_bucket_path field is deprecated: it's still accepted on create and still emitted in responses, but it's an alias of bucket_path and will be removed in a future major. Switch reads and writes to bucket_path.

Fixed

  • include now reaches the wire from every SDK. The shared engine dropped the find option's include clauses before sending the request, so eager-loading silently returned bare rows on Web, Node, and React Native. The option now passes through verbatim, and FindOptions gained the matching include field on iOS, Android, and React Native — parity with Web/Node. Ships in the next SDK patch release.

2026-06-09

New

  • Store-product provisioning through the monetization apply. Declared products that don't exist upstream are now created by apply: each is registered with RevenueCat (attached to the right app automatically), and App Store products that declare store_metadata.push_to_store (plus duration + subscription_group_name for subscriptions) are created in App Store Connect through RevenueCat's store connection — one apply provisions entitlements, offerings, packages, paywall drafts, AND the store products they sell. Store catalog writes are held to a stricter gate than other gated ops: they never run off an up-front confirm — the apply waits until you explicitly approve the started run (re-call apply with confirm, or amba monetization apply --confirm). The plan now returns a human_floor checklist for what no API can do — pricing, agreements/banking/tax, app review, and store SKUs outside the App Store — each with the exact console location (your declared store_metadata.price is echoed into the checklist). Store products join the three-way diff like every managed object: display-name updates apply automatically, removals archive (soft — the store product is untouched), and out-of-band edits surface as drift. Blocking gaps (a product referenced but never declared, or a store with no connected RevenueCat app) still fail fast with 422 MONETIZATION_STORE_FLOOR and the exact fix.
  • Your app's MCP: exposure allowlist, function tools, and surface config. The per-app agent surface (Your app's MCP) now exposes collections and deployed functions behind an explicit allowlist — nothing is exposed by default; opt collections/functions in via PUT /admin/projects/:id/app-mcp/exposure (or the amba_app_mcp_set_exposure MCP tool). Exposed deployed functions become callable tools (<app>_fn_<name>) that invoke through the same execution path as every other caller — and they're fully typed when the function declares mcp: { description, input_schema } in its deploy metadata (supported schema subset validated at deploy time; promote restores the annotation that shipped with a version). New per-app surface config (GET/PATCH .../app-mcp/config, amba_app_mcp_get_config / amba_app_mcp_update_config): an enabled kill switch, an auth_mode restriction (all / client_only / developer_only), and a hostname slug that reserves https://<slug>.mcp.amba.host/mcp for your app — hostname availability is rolling out, and the path-addressed endpoint keeps working unchanged either way.
  • Spend ceilings now enforce, and usage is fully visible. The ceiling you set with amba_billing_set_ceiling (or PUT …/billing/ceiling) is no longer advisory: when the current period's overage cost reaches it, the project degrades to read-only mode — metered writes (event tracking, collection inserts/updates, media uploads, push sends, new signups) return 402 with a machine-readable payload (code, current usage, ceiling, reset date) while reads and deletes keep working. Tier quotas enforce through the same path on throttle mode (402 TIER_QUOTA_EXCEEDED). Two control-plane webhook events — billing.ceiling_warning (80%) and billing.ceiling_reached (100%) — fire once per billing period so you can alert before the flip. GET …/billing/status (and amba_billing_status, amba billing status) now returns current-period usage and cost by meter, the billing period and reset date, percent of ceiling consumed, a projected end-of-period overage, and the live enforcement state; the console gains a per-project Usage page showing the same. See Billing & Usage.
  • Web subscriptions. Sell on the web through your own Stripe Billing account — the path RevenueCat documents for web checkout — and web purchases grant the same Amba entitlements as mobile ones: same has() check, same auto-reward cascade, same segments and webhooks. Connect with amba_integrations_configure({ provider: "stripe_billing", … }), map your Stripe price to an Amba product (store_product_refs.web), and pass amba_user_id in the checkout metadata. Ingest is signature-verified, idempotent, and order-safe. See Web Subscriptions.
  • Durable monetization apply. POST /admin/projects/:id/monetization/apply (and amba monetization apply / amba_monetization_apply) now starts a durable, pollable apply instead of writing in-request: the response carries an operation_id to poll via GET /operations/:operationId (the CLI polls for you). Writes are paced against RevenueCat's API rate limits and carry per-step idempotency keys, so a large plan applies safely over several minutes and an interrupted apply resumes without double-creating anything. Destructive changes now wait for confirmation: apply without confirm reports confirm_required: true and holds the gated ops (up to 24h) until you re-call apply with confirm = plan_hash; a confirmation that no longer matches the plan is rejected with nothing written. One apply runs at a time per project (409 MONETIZATION_APPLY_IN_PROGRESS carries the in-flight operation_id). Migration note: the apply endpoint now returns 202 with { operation_id, status, confirm_required, gated, refused } — poll the operation for the final applied / skipped_existing / gated_applied counts that previously came back inline, and confirm-required / invariant outcomes now settle the operation instead of failing the request.
  • Your app's MCP: end-user scope, vector search, faster connects, metering. The per-app agent surface (Your app's MCP) now serves two credential modes: the existing developer scope, and a new end-user scope (X-Api-Key + the user's session token) whose tools run through the same enforcement path as the client SDK — collection access policies hold with no bypass, so an in-app assistant only ever sees the signed-in user's data. Collections with a vector column automatically gain a <collection>_find_nearest similarity-search tool. The tool surface is now built from a per-app manifest cached with explicit invalidation on schema changes (connects are faster; a schema change still shows on the next tools/list). Usage is metered: tool calls appear as the new agent tool calls axis in amba_billing_status, amba billing status, and the console billing page.
  • Cursor pagination from page one. Collection list/find responses (REST and the app-MCP tools) now return next_cursor on the first page whenever the query has a single-column order — previously only continuation pages carried it, so there was no way to start a cursor chain. The app-MCP list/find tools default to created_at desc so agents paginate out of the box.
  • Agent build reference. An agent builds an app walks the entire journey — account, project, data model, SDK install, identity, XP + streaks, push, live updates, ship checklist — with every MCP tool call and SDK method taken from the live surface. Executable top to bottom by a coding agent.
  • Capability Index. /capabilities maps every shipped surface — identity, engagement, gamification, economy & monetization, social, analytics, infrastructure, and the agent/developer surface — on one scannable page with one-liners and links.
  • Generated OpenAPI reference. The full API surface is now published as a machine-readable OpenAPI 3.1 document, generated directly from the live route registrations — fetch it at https://api.amba.dev/openapi.json (no auth, CORS-open) or browse the new endpoint index with per-endpoint auth requirements.
  • Live updates are generally available for shipped apps. Long-lived subscriptions now connect to a dedicated realtime host (realtime.amba.host) with no request-duration ceiling, so Amba.collection().subscribe(), conversation subscriptions, and Amba.gamification.subscribe() stay open as long as your app does. The SDK routes there automatically when pointed at the default production API; a custom apiUrl keeps live updates on that same origin. Ships in @layers/amba-web 4.0.6, @layers/amba-node 4.0.7, and @layers/amba-react-native 4.0.5 (Expo inherits via React Native). See Live Updates.

Improved

  • React Native: offerings + Restore Purchases on npm. Amba.offerings() and Amba.entitlements.restore() (with the Offering* / RestoreResult types) are now published in @layers/amba-react-native 4.0.5 — parity with Web and Node.
  • SDK + tooling patch wave. @layers/amba CLI 4.0.4 (monetization plan/apply/adopt, payments setup/balance/payouts — amba --version now reports the real version), @layers/amba-mcp 4.0.6 (monetization, payments, auto-MCP collection tools, AI transcription + vision, media catalogs, translations), @layers/amba-shared 4.0.4, and @layers/amba-core 4.0.6 pick up everything shipped on the platform since their last publish.

Fixed

  • Collection row updates now merge JSON object columns (merge-patch). PATCH on a collection row used to replace a jsonb column wholesale, so two devices each updating their own key clobbered each other. Object values targeting jsonb columns now merge into the stored object — shallow, atomic, on every update path (single-row, bulk, update_many, and transaction update ops, client and admin alike). Arrays, scalars and null still replace the column value. Need the old overwrite behavior? Pass ?objects=replace (or objects: "replace" on a transaction op / the amba_*_update_row MCP tools). Matches the merge semantics user properties already had. See the client API reference.

2026-06-07

New

  • Monetization gated destructive apply. amba monetization apply can now make destructive changes — detaching a product, archiving an entitlement or offering, and removing a package — behind an explicit confirmation. They run only when you re-apply with --confirm (or confirm set to the plan_hash); without it they're reported but not executed. Confirmed applies enforce an ordering invariant before any write: Amba never archives the offering customers currently see (RevenueCat has no API to move the default pointer — do it in the dashboard) and never detaches the last product a live customer resolves unless you pass --allow-detach-live. New --reconcile amba|adopt controls how out-of-band drift is reconciled. If you configure a sandbox RevenueCat project, destructive changes are tried there first (with a synthetic purchase→entitlement-resolve check) before production. Setting the default offering and publishing a paywall live remain dashboard steps (no RevenueCat API) and are surfaced with the exact instructions.

  • Subscription products, offerings & a paywall read. Declare a provider-neutral product catalog Amba owns: define an entitlement, declare the products that unlock it (with per-store identifiers), and group them into an offering your paywall renders. New client read Amba.offerings() returns the offering + packages + the product behind each, in a neutral shape. Configure it agentically (amba_entitlements_define, amba_products_create, amba_entitlements_map_product, amba_offerings_create / amba_offerings_list) or via /admin/projects/:projectId/subscriptions/*. Any grant carrying a product_id — a store webhook or a server grant — now resolves to the mapped entitlement automatically, so every purchase path lands on the same entitlement set.

  • Restore Purchases. New Amba.entitlements.restore() (web / node / RN / Expo; iOS + Android in SDK 4.1.0) and POST /client/entitlements/restore re-sync the user's owned entitlements from the configured subscription service and return the active set — the App Store 3.1.1 requirement. Fail-closed: a transport failure leaves access exactly as it was, never a silent unlock or revoke.

  • Reward bundles on subscribe. Entitlement grants now emit neutral entitlement.granted / subscription.started / subscription.renewed events. Bind a currency/XP grant rule (or any event rule) to them to auto-reward new subscribers — grant currency, move to a segment, fire a push — with no glue. Idempotent: a redelivered webhook or repeat grant rewards at most once per billing period.

  • Amba Payments — accept payments in your app. Your app can now collect payments from its users with Amba as the rail: your app is the seller, Amba takes a configurable platform fee, and the money settles to your own connected account. Onboard in one flow — amba payments setup (or the amba_payments_account_create + amba_payments_create_onboarding_link MCP tools) creates your account and returns a hosted setup link you complete once. Then create charges server-side with application_fee_amount, and read your balance and payouts with amba payments balance / payouts. The charge returns a client_secret your app completes on-device with the platform's standard payment sheet (any Stripe-compatible client SDK). See Payments. Availability is enabled per platform; check amba payments status if a call reports payments aren't enabled yet.

  • Metered overage collection. When a project's spend mode is overage_bill, usage past your included quotas is now tallied into a per-period usage ledger and reconciled daily onto your upcoming invoice — so overage genuinely rolls into your next invoice instead of being served for free. GET .../billing/status gained three honest figures: recorded_overage_usd_this_period (tallied), billed_overage_usd_this_period (actually added to Stripe), and metered_billing_live (whether charging is enabled yet). Set a spend ceiling for hard 429 throttling instead of accruing charges. Metered charging is rolling out behind a flag — until it's switched on, usage is tracked and visible but nothing is billed.

  • Monetization apply (write to RevenueCat). amba monetization apply (and amba_monetization_apply, POST /admin/projects/:id/monetization/apply) now pushes your declared subscription config to RevenueCat. Additive ops (create entitlements, offerings, packages, and paywall drafts; attach products) apply automatically. Pass the plan_hash from a fresh plan; apply refuses if RevenueCat drifted since then, hard-fails if a referenced store product isn't registered yet, reads back every write to confirm it landed, and stops on the first failure without rolling back (the additive half-state still resolves your current offering). plan now returns a plan_hash. Apply needs a read-write RevenueCat key — set it as secret_api_key_write on the integration, or use one full-access key for both read and write.

Changed

  • store value "stripe""web". The entitlement store field's vendor-named "stripe" value is now the neutral "web" (covering any non-native checkout). Existing rows are migrated automatically and the server still accepts "stripe" on write (folding it to "web"), so no client change is required — but new code and SDK types use "web".

2026-06-06

New

  • Your app's MCP (preview). Every collection in your app is now automatically a set of typed agent tools at your app's own MCP endpoint — https://mcp.amba.dev/app/<project-id>/mcp. Create a recipes collection and the endpoint immediately exposes recipes_list / get / find / insert / update / delete / aggregate, with a typed, per-column where schema so an agent queries your data without writing query strings by hand. Tools are generated live from your schema at connect time — add a collection and the next tools/list reflects it. Admin-scoped today; end-user scope, per-collection access policies, and typed tools for deployed functions are coming. See Your app's MCP.
  • Live updates on React Native & Expo. Amba.collection(name).subscribe(), Amba.messaging.conversation(id).subscribe(), and Amba.gamification.subscribe() now ship in @layers/amba-react-native and @layers/amba-expo with the exact same surface and change shape as Web and Node. On mobile the live connection rides the platform's native networking, so it works in release builds with no extra setup or peer dependency, and reconnects with backoff just like Web. See Live Updates.
  • Audio transcription via the managed AI proxy. The AI surface now proxies speech-to-text alongside image generation and text-to-speech: upload an audio file and get a transcript back, with your provider key kept server-side and per-call usage metered per audio minute. Same managed pattern as the other media endpoints.
  • Google Gemini in named prompts. Register a prompt against gemini and invoke it by name like any other provider — amba builds Gemini's distinct request shape for you (system instruction + multi-turn content + variables), including multimodal image input, and parses the response back to the common result. Previously Gemini was reachable only through the raw passthrough.
  • Monetization control plane (preview). Manage your subscription config — entitlements, products, offerings, packages, paywalls — as Infrastructure-as-Code on top of RevenueCat. amba monetization plan previews the three-way diff (declared vs adopted baseline vs live) with a store-floor preflight and drift; drift surfaces out-of-band dashboard edits (a daily background sweep records them automatically); export snapshots the live config to a declarative bundle; adopt records the live config as your managed baseline. Also wired into the promotion bundle and exposed as MCP tools (amba_monetization_*). Phase 1 is read-only against RevenueCat — plan/drift/export/adopt never write to RevenueCat (adopt writes only Amba's own state). Pushing declared changes back to RevenueCat ("apply") is coming in a later phase.
  • Automatic offline queue. Turn on Amba.offline.enable() and a collection write or track() that fails because the device is offline is buffered to a durable on-device outbox instead of throwing — then replayed in order on reconnect. Replays are idempotent, so a write that reached the server before the connection dropped is never applied twice. Web auto-flushes on the browser online event; React Native drives flush() from your connectivity listener. Opt-in and additive. Web + React Native + Expo + Node SDKs.
  • Optimistic update helpers. New framework-agnostic withOptimistic({ apply, mutate, rollback }) applies a local change immediately, fires the real write, and rolls the local change back automatically if it fails — plus Amba.collections.optimisticInsert / optimisticUpdate / optimisticDelete convenience helpers for the common single-write case.
  • Push-token auto-rotation. Re-register the device push token whenever the OS rotates it (reinstall, restore, key roll) so notifications keep arriving. Web listens for the service-worker pushsubscriptionchange; React Native wraps your token-refresh listener; Expo's one-call Amba.enablePushAutoRotation() wires expo-notifications for you. Re-registration is idempotent.

See the Offline & resilience guide.

  • Realtime gamification. Subscribe to a user's live XP, level, achievement, and streak changes over one stream — no polling. Amba.gamification.subscribe((change) => { … }) on the web and Node SDKs delivers each change (with its kind and new state) the moment it happens, and only ever surfaces the signed-in user's own updates. Backed by GET /v1/client/realtime/gamification. See Realtime.
  • Multi-collection transactions. Commit writes across several collections as one atomic batch — the whole set applies, or none of it does. Amba.collections.transaction([ … ]) (web + Node) and POST /v1/client/collections/transaction take an ordered list of insert / update / delete ops, each with optional compare-and-set and upsert. See Collections (SDK).
  • Related rows in one query. Add include to a collection read to eager-load related rows in a single round-trip instead of an N+1 fan-out. See Collections (Client API).
  • Per-language content. Attach translations to a content item and Amba serves the reader's language automatically from Accept-Language (BCP-47), falling back to the base item when there's no match. See Content (Client API).
  • Admin collection-row tools. The MCP toolset gained amba_admin_update_row, amba_admin_delete_row, amba_admin_bulk_update, and amba_admin_bulk_delete, so an agent can manage row data end-to-end — not just insert and read.

Fixed

  • Subscription webhooks are now idempotent and order-safe. Subscription events are delivered at-least-once and can arrive out of order; ingest now deduplicates each event and refuses to let an older event overwrite newer entitlement state. A redelivered or late event can no longer silently revoke an active subscriber.
  • Refunds revoke access. A refund now marks the entitlement inactive immediately (previously a refunded subscription could stay active). A cancellation correctly keeps access until the period's expiration_date rather than revoking on the spot.
  • Expiry-aware reads. GET /client/entitlements now derives is_active from the expiration date, so a lapsed subscription never reads as active even before its expiry event lands. ?active_only=true filters to currently-active grants server-side.

Changed

  • Paywall engagement events are now recorded with neutral paywall_<event> names (previously superwall_<event>), and subscription user properties use neutral subscription_* keys (previously rc_*). Existing segment/rule references to the old names keep working on data written before this change; update rules to the neutral names going forward.

2026-06-05

New

  • AI vision (image input). Send images to a registered prompt running on a vision-capable model. Pass images (each { url } or { data, mime }) on the web + Node SDK ai.*.create call — or supply messages with content blocks ({ type: 'image', url | data, mime? }) directly — and Amba maps each image to the model's native format. Sending an image to a text-only model returns a clear ai_model_not_multimodal error instead of silently dropping it. Works for Anthropic, OpenAI, and Gemini vision models; the amba_ai_prompts_invoke MCP tool gained an images parameter for testing. See AI proxy → Vision.
  • On-device local notifications. Schedule reminders that fire on the device itself — no server round-trip — with Amba.notifications.scheduleLocal({ title, body, trigger }), then cancelLocal(id) and listScheduledLocal(). Triggers can be an absolute time ({ at: Date }) or a delay ({ inSeconds, repeats? }). Available on the React Native, Expo, and web SDKs; iOS and Android schedule fully (even while the app is closed), and the web SDK schedules within the browser's capabilities and reports its mode (scheduledVia). Distinct from remote push — use local for device-owned timing (streaks, focus timers), push for server-owned timing. See Local notifications.
  • Event dry-run / explain. Preview what an event would trigger before you fire it. Amba.events.explain(event, properties, { userId }) (web + Node) evaluates the rule engine — XP rules, currency grants, feed rules, streaks, and webhook subscriptions — against a candidate event and returns the would-be effects without committing any side effect. Matched rules that a per-user daily limit, cooldown, or balance cap would suppress carry a note. Backed by POST /v1/client/events/explain (and the admin equivalent) and the read-only amba_events_explain MCP tool. See Events → Explain.
  • AI cost visibility. Every buffered AI response now carries a cost_usd field — the dollar cost of the call, computed from token usage — so you can show per-call spend or sum it per user without a separate metrics call. Surfaced on the web + Node SDK AiMessageResponse type. See AI proxy.
  • Per-prompt AI budgets. Cap a registered prompt's spend with a per-period USD ceiling (monthly, daily, or lifetime total). Once the period's spend reaches the budget, invocations are denied with a clear ai_budget_exceeded error until the period resets — so a prompt you expose to your app can't run away with spend. Off by default (unlimited). Manage it via the new budget endpoints or the amba_ai_prompts_set_budget / amba_ai_prompts_get_spend MCP tools.
  • Media catalogs. Group media assets into a named, slug-addressable catalog your app fetches in one call — instead of hard-coding asset URLs in client code. Items stay in the order you set; each resolves to a stable, long-cacheable public URL. Curate with the amba_media_catalogs_* tools and read from your app with Amba.media.catalog(slug) (GET /v1/client/media/catalogs/:slug). See Media → Catalogs.

2026-06-04

New

  • AI — structured JSON output & streaming. Force a registered prompt to return parseable JSON with response_format (json_object or json_schema), and opt into a Server-Sent Events stream with stream: true — usage stays metered server-side. See AI proxy and the new client AI reference.
  • Async operation handles. Side-effecting actions (starting with domain purchase) hand back an operation_id you poll to succeeded / failed instead of guessing. See Operations.
  • Configurable XP level curve. Set xp_per_level or explicit level_thresholds per project, and read the effective curve from the client. See XP and Levels.
  • Collection access policies (public catalogs). read_policy: "public" lets every signed-in user read a collection; write_policy: "authenticated" opens writes. The default stays strict per-user. See Collections (Admin API).
  • Idempotent collection writes. Pass an Idempotency-Key header (or idempotency_key body field) on a collection insert and a retry can never create a duplicate — the replay returns the original row.
  • Scoped reset. Reset one user's state to zero (DELETE …/users/:id/reset, optionally ?delete=true), or empty a single collection's rows (DELETE …/collections/:name/data) — instead of the all-or-nothing sandbox wipe. See Users (Admin API) and Collections (Admin API).
  • Seed a cohort. POST …/users/cohort mints N anonymous users sharing properties (and optional segments) in one call.
  • Daily content batches. Set batch_size on a content schedule to deliver N distinct items per tick (delivered as an array). See Content scheduling.
  • Message read receipts. GET …/messages/:id/receipts returns who has seen a message for a "seen by N of M" UI. See Messaging (Client API).
  • SDK — collection upsert, deleteWhere, restore. The web and Node SDKs gained typed Amba.collections.upsert(), deleteWhere(), and restore(). See Collections (SDK).
  • CLI — infrastructure as code. amba export / amba diff / amba apply manage your project's reusable configuration declaratively (amba.config.json), and amba functions deploy now accepts a directory (with --entry). See the CLI reference.

2026-05-30

Fixes

  • Expo Go. Amba.configure() now initializes cleanly on first call across Expo Go, development, and standalone builds. If you're on an earlier @layers/amba-expo 4.0.x, upgrade with npx expo install @layers/amba-expo — no code changes required on your side.

New

  • Experiments — A/B testing with significance. Define weighted variants, get sticky per-user assignment, log exposures, and read per-variant conversion rates with a built-in two-proportion z-test. See Experiments.
  • Environment promotion. Export a project's declarative configuration bundle and import it into another project (dev → prod) in one call — currencies, achievements, collection schemas, content libraries, flags, and more. See Environment Promotion.
  • Messaging — threads, attachments, typing, reactions. Reply in threads with parent_message_id, attach files, broadcast a typing signal, and add emoji reactions. See Messaging.
  • Auth — email + password account linking. Amba.auth.linkEmailPassword(email, password) upgrades an anonymous session to an email-identified account in place, preserving the guest's data. See Account linking.
  • Collections — return=minimal. Pass ?return=minimal (or Prefer: return=minimal) on single or batch inserts to trim the response to row ids — keeps large-row migrations inside an agent's token budget. See Collections (Admin API).
  • Users — admin create. POST /admin/projects/:projectId/users (MCP: amba_users_create) mints a seed / system user to attribute migrated rows to. See Users (Admin API).

2026-05-29

Breaking change — Admin collections: includeDeleted now defaults to false. The Admin list rows and count rows endpoints used to return soft-deleted rows by default; they now exclude them. If you relied on seeing soft-deleted rows from an admin call, pass includeDeleted: true explicitly. The client (SDK-facing) surface has always defaulted to false and is unchanged.

New

  • Collections — atomic upsert. Insert with on_conflict (ignore or update) and a conflict_target to insert-or-update in a single call. See Collections (Admin API).
  • Collections — compare-and-set. Conditional updates that only apply when the row still matches an expected snapshot, so concurrent writers don't clobber each other. See Collections (Admin API).
  • Collections — group-by aggregation. Roll rows up with count, sum, avg, min, and max over a group-by key.
  • Collections — client-side bulk insert. Insert many rows at once via /batch. Both single-row and batch insert return a clear 409 on a unique-key clash, so a duplicate always surfaces immediately.
  • Economy — exactly-once grants & spends. Pass an idempotency_key on a currency grant or spend and a retry can never double-apply. See Idempotent grants and spends.
  • Economy — spendable initial balance. A currency's initial_balance is now spendable: it's credited to the ledger the first time a balance is touched. See Spendable starting balances.
  • Functions — filter logs by request. amba functions logs <name> --request-id <id> narrows a function's logs to a single request (r_...), and works with --tail. See the CLI reference.

On this page