---
title: "Web SaaS Guide"
source: https://docs.myappaffiliate.com/web-saas
docs: "MyAppAffiliate — Developer Documentation"
index: https://docs.myappaffiliate.com/llms.txt
---
# Web SaaS Guide

End-to-end: a creator shares a link to your SaaS, a visitor signs up and subscribes,
and the creator earns a commission on every invoice — renewals included. No mobile
app, no app store. Works with Stripe, Paddle, or anything that can tell us your user
id.

## The loop

```
creator link  https://yourapp.com/?via=LUMI
   → landing page       (Web SDK captures ?via= and persists it)
   → signup             (identify(userId) binds your user id)
   → checkout           (your billing provider carries that same id)
   → paid invoice       (provider webhook → our API → commission)
   → renewals           (every recurring invoice keeps paying the creator)
   → dashboard + CSV    (pending → matured → paid out)
```

**Prompt for an AI coding agent**

```text
Integrate MyAppAffiliate into my project.

Documentation (read these first, they are the source of truth):
- Page: https://docs.myappaffiliate.com/web-saas.md
- Full docs index: https://docs.myappaffiliate.com/llms.txt

Task: Wire MyAppAffiliate through my web SaaS end to end: capture ?via= on the landing page, identify the user at signup, carry that same user id into my billing provider's checkout, and register the revenue webhook. Walk the steps in order and show me the code for each.

Rules:
- Follow the documented API exactly — no invented method names, endpoints, parameters or field names.
- Match the conventions already used in my codebase.
- Ask me for my SDK key instead of guessing, and never hard-code it — read it from config/environment.
- Do NOT set an API base URL anywhere. Every SDK compiles the production host in; a staging or self-hosted host belongs in a build setting, not in code.
- Tell me afterwards which steps I still have to do by hand (dashboard settings, capabilities, webhook configuration).
```

## 1. Give creators their link

Each affiliate gets a code (e.g. `LUMI`). Their link is just your site plus a query
param — no redirect service needed:

```
https://yourapp.com/?via=LUMI
```

Branded `go.myappaffiliate.com` short links work too (they carry a `claim_token`
instead); the Web SDK handles both, on any route.

## 2. Capture on the landing page

On a plain landing page, a script tag is the whole integration — no build step:

```html
<script
  src="https://cdn.jsdelivr.net/npm/@myappaffiliate/sdk-web@0/dist/sdk.js"
  data-api-key="pk_live_…"
  async
></script>
```

In an app frontend, install it instead:

```bash
npm i @myappaffiliate/sdk-web
```

```ts
import { myAppAffiliate } from "@myappaffiliate/sdk-web";

myAppAffiliate.start("pk_live_…");
```

One call in your app shell or root layout. It captures `?via=` (and `claim_token`) on
load *and* on client-side route changes, then persists the winner in `localStorage`,
so the referral survives navigation, a closed tab, and the days between landing and
signup. There is no API URL to configure. Details: [Web SDK](https://docs.myappaffiliate.com/sdk-web).

## 3. Identify at signup

When the account is created, bind **your user id** to the attribution. Client-side:

```ts
await myAppAffiliate.identify(user.id);
```

…or server-side with the [Node SDK](https://docs.myappaffiliate.com/sdk-node), which also picks the referral out of
the request URL for you:

```ts
await myAppAffiliate.trackSignup({ userId: user.id, from: req.url });
```

This id is the join key for everything that follows — it must be the exact string your
billing provider reports back to us in step 4.

## 4. Carry the same id into checkout

**Stripe:**

```ts
await stripe.checkout.sessions.create({
  mode: "subscription",
  line_items: [{ price: "price_…", quantity: 1 }],
  subscription_data: { metadata: { customer_user_id: user.id } },
  client_reference_id: user.id,
  success_url: "https://yourapp.com/welcome",
  cancel_url: "https://yourapp.com/pricing",
});
```

**Paddle:**

```ts
await paddle.transactions.create({
  items: [{ priceId: "pri_…", quantity: 1 }],
  customData: { customer_user_id: user.id },
});
```

**Neither, if you'd rather skip this step:** both providers fall back to their own
customer id, so `identify(stripeCustomerId)` / `identify(paddleCustomerId)` in step 3
works instead. Pick whichever is less plumbing in your codebase.

## 5. Register the webhook

- **Stripe** → Developers → Webhooks → Add endpoint:
  `https://api.myappaffiliate.com/webhooks/stripe/<appId>`, events `invoice.paid`,
  `charge.refunded`, `customer.subscription.deleted`, `checkout.session.completed`.
- **Paddle** → Developer tools → Notifications:
  `https://api.myappaffiliate.com/webhooks/paddle/<appId>`.

Paste the provider's signing secret into your MyAppAffiliate app settings; every
delivery is signature-verified. Full details, including the normalized event mapping
for all providers, are in [Billing & Webhooks](https://docs.myappaffiliate.com/webhooks).

## 6. Watch it pay

- The [founder dashboard](https://docs.myappaffiliate.com/dashboard) shows the funnel (clicks → signups → paid),
  revenue, and per-creator earnings.
- Creators get their own scoped view with earnings and next-payout date.
- Payouts are a CSV export of matured commissions — idempotent, reconciles to the
  payout total.

Commission is `amount × rate_bps / 10000`, attributed to the referral inside the
attribution window, created `pending` and `matured` after the hold period — so refunds
inside the hold never pay out.

## Checklist

1. `myAppAffiliate.start("pk_live_…")` in your app shell
2. `identify(userId)` at signup (or `trackSignup` server-side)
3. That same id reaching your billing provider (metadata, or use theirs)
4. Webhook endpoint registered + signing secret saved
5. Test end-to-end with a test-mode subscription → commission appears on the dashboard
