SDKs
One SDK per platform, all with the same two-call surface. Pick yours:
| SDK | Platform | Guide |
|---|---|---|
| Swift | iOS 15+ apps | iOS SDK |
| Kotlin | Android apps | Android SDK |
| React Native | iOS + Android from one codebase | React Native SDK |
| Flutter | iOS + Android from one codebase | Flutter SDK |
| Web | Browser — landing pages & SaaS frontends | Web SDK |
| Node | Server-side — SaaS backends | Node SDK |
The whole integration is two calls
start(apiKey) → once at launch
identify(userId) → once you know who the user isThat is the entire required surface, on every platform. There is no third step.
start takes your SDK key and nothing else. It generates a stable device id,
claims the referral from an incoming link or ?via= code, retries anything a
previous offline launch failed to deliver, and — on a fresh install with no link
to go on — asks the API for a deferred match. You do not orchestrate any of it.
identify binds your user id to that attribution. This is the join key for
every revenue event that follows. It must be the same string your billing
provider reports back to us — see Billing & Webhooks for the exact
field per provider.
You never type an API URL
The production host is compiled into every SDK. Nothing about our
infrastructure belongs in your source code, so there is no baseUrl argument
to get wrong, copy between environments, or ship pointing at staging.
To point at a staging or self-hosted API, use the escape hatch that already belongs to your build configuration rather than a source file:
| SDK | Override |
|---|---|
| iOS | MyAppAffiliateAPIBaseURL in Info.plist |
| Android | com.myappaffiliate.API_BASE_URL manifest meta-data |
| Flutter | --dart-define=MYAPPAFFILIATE_API_BASE_URL=… |
| React Native | apiBaseUrl option on start |
| Web | data-api-base-url on the script tag, or the apiBaseUrl option |
| Node | MAA_API_BASE_URL env var |
Most SDKs will also read the key from the same place, so start() can take
no arguments at all.
When you need more than two calls
Everything below is optional. Reach for it when the situation calls for it, not because setup demands it.
attribute(url)— hand the SDK an incoming deep link. Wired for you by the SwiftUI modifier (iOS), the manifest provider (Android), and thelinkingoption (React Native); call it yourself in UIKit or a custom router.applyCode(code)— a creator code typed into a field ("LUMI"). Works with zero deep-link setup, which makes it the reliable fallback everywhere.attributedAffiliateId()— the affiliate this install belongs to, for your own UI or analytics. Attribution does not depend on you reading it.reset()— clear everything on logout or a data-erasure request.- Options — a staging host, a custom storage adapter, debug logging.
Every SDK persists a stable generated device id, and every network failure is
silent-safe: calls return false/null and never throw into the host app.
The underlying REST contract is two endpoints:
POST /sdk/install and POST /sdk/identify. The SDKs are a convenience
over them, not a requirement.