Skip to content
Sendora Cloud
Create account
Developer changelog

SDK and API releases.

Tied to SDK version numbers. Separate from the product changelog.

2026-05-14API · 1.8.0
  • Deep-link SDK surface DX polish: `fallbackUrl` now optional on `POST /sdk/links` — backend defaults from your project's apps registry (web origin > iOS App Store URL > Android Play Store URL).
  • New `GET /sdk/links/:shortcode/stats` — totals, unique clicks, deferred matches, by-OS / by-country / by-device breakdowns. Project-scoped via the public key.
  • New `POST /sdk/links/:shortcode/revoke` — idempotent soft-delete (private-content unsend). Worker cache busted on flip.
  • OpenAPI spec coverage expanded; spec version 1.8.0.
2026-05-14React Native · 0.16.0
  • Typed `linkData<T>` generic across `links.create<T>(...)` / `onLinkOpened<T>(cb)` — branch your deep-link router on a discriminated union, not casts.
  • Typed `LinkError` class with codes (`BUNDLE_MISMATCH`, `DATA_TOO_LARGE`, `EXPIRED`, `RATE_LIMITED`, `PLAN_LIMIT`, `FALLBACK_REQUIRED`, ...). `err instanceof LinkError` + `switch (err.code)` instead of `err.message.includes(...)`.
  • `links.prewarm(input, { key })` — background-mint + cache so share-row taps skip the HTTPS round-trip ActivityIndicator.
  • `links.attachLinkingApi({ onLegacyUrl })` — one-call replacement for `Linking.getInitialURL` + `addEventListener` + extract-pre-check + fallthrough.
  • `links.computeDeviceFingerprint()` baked in — no `expo-crypto` / `Dimensions` / `Intl` boilerplate per customer.
  • `links.matchDeferred()` auto-probes `react-native-play-install-referrer` (Android) + computes the fingerprint (fallback).
  • `links.revoke(shortcode)` + `links.getStats(shortcode)` — no more dashboard scraping.
  • `fallbackUrl` now optional; SDK config gains `linkDomain` for custom share hosts (e.g. `pulse.link`).
  • `examples/links-share.tsx` + `examples/links-router.tsx` shipped in the npm tarball.
2026-05-14iOS · 3.9.0
  • Typed `SendoraCloudLinks.LinkError` with `code: LinkErrorCode` — pattern-match on `.bundleMismatch / .planLimit / .rateLimited / ...`.
  • `LinkCreateInput(typedLinkData:)` Codable constructor + `event.decodedLinkData() throws -> T` typed accessor.
  • `links.prewarm(_:key:)` + `links.create(_:prewarmKey:)` — background-mint cache.
  • `links.revoke(shortcode:completion:)` + `links.getStats(shortcode:completion:)`.
  • `SendoraCloudLinks.computeDeviceFingerprint()` — canonical recipe matching Android + RN byte-for-byte.
  • `fallbackUrl` now optional. Domain-aware `extractShortcode(from:allowedHosts:)` honours `config.linkHosts`.
2026-05-14Android · 3.8.0
  • Typed `SendoraCloudLinks.LinkError(code: LinkErrorCode, ...)` — `when (err.code)` exhaustive match.
  • `links.prewarm(input, key)` + `links.create(input, prewarmKey)` — background-mint cache.
  • `links.revoke(shortcode)` + `links.getStats(shortcode)`.
  • `SendoraCloudLinks.computeDeviceFingerprint()` — canonical recipe matching iOS + RN.
  • `matchDeferred(...)` auto-computes the fingerprint when neither input is supplied.
  • Domain-aware `extractShortcode(uri, allowedHosts)` honours `config.linkHosts`.
2026-05-13API · 1.7.0
  • New SDK-facing deep-link surface: POST /sdk/links (auto-shortcode, bundle-id gated, 2KB linkData cap, 200/hr per IP, plan-limited), GET /sdk/links/:shortcode (warm-path resolve, tenant-guarded), POST /sdk/links/match (deferred match by Android Play Install Referrer OR iOS fingerprint hash, 24h window).
  • Public-key (pk_*) gated — Branch / AppsFlyer parity. Leaked key + wrong bundle = 400.
  • Successful deferred match flips click_events.matched=true so re-installs don't double-resolve.
  • OpenAPI spec coverage expanded; spec version 1.7.0.
2026-05-13React Native · 0.15.0
  • New `sendora.links` namespace — `create({ title, fallbackUrl, iosDeepLinkPath, androidDeepLinkPath, linkData, ... })` returns share URL.
  • `links.handleUniversalLink(url)` resolves a Universal Link / App Link delivery + fires `onLinkOpened` callback with the link's linkData JSON.
  • `links.matchDeferred({ installReferrer | fingerprintHash })` for cold-launch deferred deep links after install. Fires `onLinkOpened` with `isDeferred: true`.
  • Optional `iosBundleId` + `androidPackageName` in init() — forwarded to backend bundle-id gate.
2026-05-13iOS · 3.8.0
  • New `SendoraCloud.links` surface — `create(input, completion:)`, `handleUniversalLink(url:completion:)`, `matchDeferred(input, completion:)`, `onLinkOpened(_:)`.
  • Backed by new `/sdk/links/*` public-key API; warm-path resolve fills `LinkOpenedEvent.linkData` so host app routes via business id (e.g. `linkData["articleId"]`).
  • Bundle id auto-supplied from `Bundle.main.bundleIdentifier`; backend rejects if it doesn't match a registered app for the project.
2026-05-13Android · 3.7.0
  • New `SendoraCloud.links` surface — `create(input, onResult)`, `handleAppLink(uri, onResult?)`, `matchDeferred({ installReferrer?, fingerprintHash? }, onResult)`, `onLinkOpened { ... }`.
  • Package name auto-supplied from app context; backend bundle-id gate rejects mismatches.
  • Android Play Install Referrer wins over fingerprint match when both are present — 100% accurate vs probabilistic. Caller fetches via `com.android.installreferrer:installreferrer` (compileOnly).
2026-05-12Web · 2.12.0
  • hydrate(): restore the cached user when REFRESH_KEY is present even if the access token is missing/expired (was: required both). Fixes cold-start regression where a navigation that cleared the access token made the user appear signed out even though the refresh chain was alive.
2026-05-12React Native · 0.14.0
  • hydrate(): restore the cached user when REFRESH_KEY is present even if the access token is missing/expired (was: required both). Fixes the Pulse News cold-start bug where the SDK appeared signed-out on every launch and host apps minted a fresh anonymous user, fragmenting analytics across sessions.
2026-05-12iOS · 3.7.0
  • getAccessToken(): trigger refresh when the access token is missing OR past expiry (was: returned nil immediately when missing). Fixes the cold-start regression where a valid refresh token in Keychain was ignored.
2026-05-12Android · 3.6.0
  • getAccessToken(): trigger refresh when the access token is missing OR past expiry (was: returned null immediately when missing). Fixes the cold-start regression where a valid refresh token in EncryptedSharedPreferences was ignored.
2026-05-12Web · 2.11.0
  • auth.refreshAccessToken now wipes local identity on a dead-token response (INVALID_REFRESH_TOKEN / UNAUTHORIZED / HTTP_401 / RATE_LIMIT). Stops the indefinite retry loop when the stored refresh token is invalid — host app sees signed-out state instead.
2026-05-12React Native · 0.13.0
  • auth.refreshAccessToken now wipes local identity on a dead-token response (INVALID_REFRESH_TOKEN / UNAUTHORIZED / HTTP_401 / RATE_LIMIT). Pre-this fix the SDK silently retried the same dead token forever.
2026-05-12iOS · 3.6.0
  • refreshAccessToken now wipes local identity on a dead-token response (INVALID_REFRESH_TOKEN / UNAUTHORIZED / HTTP_401 / RATE_LIMIT). Stops the indefinite retry loop when the stored refresh token is invalid.
2026-05-12Android · 3.5.0
  • refreshAccessToken now wipes local identity on a dead-token response (INVALID_REFRESH_TOKEN / UNAUTHORIZED / HTTP_401 / RATE_LIMIT). Stops the indefinite retry loop when the stored refresh token is invalid.
2026-05-12API · 1.6.0
  • POST /auth-service/token/refresh: new error code INVALID_REFRESH_TOKEN (HTTP 401) with Retry-After: 60. 10s rotation grace window — replaying the predecessor within 10s of a successful rotation no longer trips reuse-detection (concurrent-refresh race).
  • Per-IP failure back-off on /auth-service/token/refresh: 5 fails in 60s → 60s 429 with Retry-After.
  • Session cleanup keeps revoked rows 7 days (was: hourly delete). Preserves reuse-detection forensics.
2026-05-08Web · 2.10.0
  • New Audiences API: sendora.audiences.list / get / create / update / delete.
  • Re-exports Audience + AudienceRule + AudienceRuleGroup types.
  • HttpClient: added patch() method.
2026-05-08iOS · 3.5.0
  • New SendoraCloudPush module — registerToken(token, platform: .ios, ...) + trackOpen(sendId, clickAction).
  • SendoraCloud.push.* surface added on configure().
  • APIClient: added get(path:completion:) overload.
2026-05-08Android · 3.4.0
  • New SendoraCloudPush module — registerToken(token, platform = ANDROID, ...) + trackOpen(sendId, clickAction).
  • SendoraCloud.push.* surface added on init().
  • Coroutine-scoped registration via existing SDK CoroutineScope.
2026-05-07iOS · 3.4.0
  • Server-managed geofences via CLLocationManager (CRUD + 20-region OS cap).
  • SendoraCloud.geofences.start() / refresh() / stop().
  • geofence.entered / .exited events fire to backend.
2026-05-07Android · 3.3.0
  • Server-managed geofences via GeofencingClient (CRUD + 100-region OS cap).
  • SendoraCloud.geofences.start(ctx) / refresh / stop / handleBroadcast(intent).
  • geofence.entered / .exited / .dwelled events fire to backend.
2026-05-06iOS · 3.3.0
  • iOS Critical Alerts — SendoraCloudCriticalAlerts.requestPermission { granted in }.
  • Send body criticalAlert: { soundName?, volume? } — APNs aps.sound{critical:1} + interruption-level=critical.
  • Apple entitlement com.apple.developer.usernotifications.critical-alerts required.
2026-05-05iOS · 3.2.0
  • iOS Live Activities (ActivityKit, push-type=liveactivity).
  • SendoraCloud.liveActivities.track(activity, activityType, externalId, userId) — watches activity.pushTokenUpdates.
  • Server-side update / end via PATCH+DELETE /push/live-activities/:id.
2026-05-05Android · 3.2.0
  • Android Live Updates — data-only FCM push routed to NotificationCompat.
  • SendoraCloud.liveActivities.start(fcmToken, activityType, attributes, contentState, ...) + handleFcmMessage(ctx, data, buildNotification).
  • ProgressStyle on API 34+; BigTextStyle fallback on older Android.
2026-05-04React Native · 0.11.0
  • Push: sendora.push.registerToken({ token, platform: 'ios' | 'android' | 'web' }).
  • Bare workflow only — Expo managed apps use webhook-bridge pattern (see /docs/push#expo).
  • Auto-track lifecycle: app.opened, app.backgrounded, screen.viewed.
2026-05-03Web SSR · 0.2.0
  • @sendoracloud/sdk-web-ssr — HttpOnly-cookie sessions for Next.js / Remix / SvelteKit.
  • createSendoraServerClient(cookies(), { publicKey }) — server-side identify + track auto-binding.
  • Edge middleware sendoraMiddleware({ protected, loginPath }).
2026-05-08API · 1.5.0
  • OpenAPI spec coverage expanded — full server-to-server push surface now in spec: /orgs/:orgId/push/{send,sends,sends/:id,sends/stats,sends/delivery-health,templates,ab-tests,settings,vapid,live-activities,geofences}.
  • SDK-facing public push endpoints in spec: /push/track-open, /push/live-activities/start-token, /push/geofences/{list-for-device,event}.
  • Audiences CRUD in spec: /orgs/:orgId/audiences.
  • New schemas: PushSendInput, PushSend, PushTemplate, PushAbTest, PushSettings, PushDeliveryHealth, LiveActivity, Geofence, Audience.
  • Path drift fix: /sms/send → /orgs/:orgId/sms/send; /sms/suppress* → /orgs/:orgId/sms/suppressions* (matches real backend org-scoping).
2026-05-08API · 1.2.0
  • OpenAPI 3.1 spec at /api/v1/docs/openapi.json.
  • Push: /push/sends/delivery-health, DELETE /push/sends/:id (cancel scheduled), GET /push/sends/:id.
  • Automation IaC: GET .../export, POST .../import (idempotent by name); workflow-bundle.v1.json schema.
  • Audiences CRUD on /orgs/:orgId/audiences.
  • Webhook event catalog canonical at /docs/webhooks (~30 event types across push / LA / geofence / email / sms / auth / workflow).
2026-04-15Web · 1.0.0
  • Initial GA.
  • identify / track / link APIs with background retries.
  • Automatic consent attachment on every event.
2026-04-15iOS · 1.0.0
  • SwiftPM package shipped.
  • APNs token management + silent push support.
  • Deferred deep linking via AASA.
2026-04-15Android · 1.0.0
  • Maven Central publish.
  • FCM token registration + refresh.
  • Install referrer + assetlinks handshake.
2026-04-15API · v1
  • OpenAPI 3.1 spec published.
  • /v1/events, /v1/identify, /v1/links, /v1/notifications GA.
  • HMAC-signed outbound webhooks with exponential backoff.