---
title: "SDKs"
source: https://docs.myappaffiliate.com/sdk
docs: "MyAppAffiliate — Developer Documentation"
index: https://docs.myappaffiliate.com/llms.txt
---
# SDKs

One SDK per platform, all with the same two-call surface. Pick yours:

| SDK | Platform | Guide |
|---|---|---|
| Swift | iOS 15+ apps | [iOS SDK](https://docs.myappaffiliate.com/sdk-ios) |
| Kotlin | Android apps | [Android SDK](https://docs.myappaffiliate.com/sdk-android) |
| React Native | iOS + Android from one codebase | [React Native SDK](https://docs.myappaffiliate.com/sdk-react-native) |
| Flutter | iOS + Android from one codebase | [Flutter SDK](https://docs.myappaffiliate.com/sdk-flutter) |
| Web | Browser — landing pages & SaaS frontends | [Web SDK](https://docs.myappaffiliate.com/sdk-web) |
| Node | Server-side — SaaS backends | [Node SDK](https://docs.myappaffiliate.com/sdk-node) |

## The whole integration is two calls

```
start(apiKey)        → once at launch
identify(userId)     → once you know who the user is
```

That 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](https://docs.myappaffiliate.com/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 the `linking`
  option (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`](https://docs.myappaffiliate.com/api). The SDKs are a convenience
over them, not a requirement.
