# Integrate your app with MasterPack

MasterPack turns your app into a subscription business without you touching
payments: subscribers sign in with their MasterPack account, and you get paid
monthly based on how much they actually use your app.

Two integration rules:

1. **MasterPack is your only sign-in.** No email/password of your own, no other
   social logins. This is a listing requirement (it's how usage — and therefore
   your payout — is attributed).
2. **The SDK's heartbeat engine runs on every page.** No heartbeats → no
   measured usage → no payout.

Throughout this guide, `$BASE` is the MasterPack origin you fetched this
document from (production: `https://masterpack.app`), and `$GATE_URL` is
the auth gate origin listed in `$BASE/llms.txt`.

## 1. Register (agents: start here)

```bash
curl -X POST $BASE/api/v1/registrations \
  -H 'content-type: application/json' \
  -d '{
    "name": "My App",
    "url": "https://myapp.example",
    "tagline": "One line that sells it.",
    "description": "At least 40 characters describing what the app does.",
    "category": "Productivity"
  }'
```

Response: `claim_url` (open in a browser — the human signs in and claims the
app), `poll_url` + `poll_token` (poll every ~5s):

```bash
curl $BASE/api/v1/registrations/{id} -H "Authorization: Bearer $POLL_TOKEN"
```

Once claimed, the poll response includes **`api_key` exactly once** — store it
as `MASTERPACK_API_KEY`. You also get `app_id` and `client_id`.

## 2. Add the SDK

```bash
npm install @masterpack/sdk
```

Sign-in (browser):

```ts
import { MasterPackAuth } from "@masterpack/sdk";

const auth = new MasterPackAuth({
  gateUrl: GATE_URL,            // MasterPack auth origin
  clientId: CLIENT_ID,          // from registration
  redirectUri: `${location.origin}/callback`,
});

// "Sign in with MasterPack" button:
auth.beginLogin().then((url) => location.assign(url));

// on /callback:
await auth.completeLogin(location.href);
location.replace("/");

// everywhere else:
const session = await auth.ensureFreshSession(); // null → show the button
session.user; // { sub, displayName, tier: "basic" | "premium" }
```

Heartbeats (usage → your payout):

```ts
import { HeartbeatEngine, browserEnv } from "@masterpack/sdk";

const engine = new HeartbeatEngine(browserEnv(`${GATE_URL}/api/beats`), {
  appId: CLIENT_ID,
  sid: session.sid,
  getAccessToken: () => auth.getSession()?.accessToken ?? null,
});
engine.start();
```

Backend verification (optional, for API routes):

```ts
import { createTokenVerifier } from "@masterpack/sdk/server";
const verify = createTokenVerifier({ gateUrl: GATE_URL, clientId: CLIENT_ID });
const user = await verify(bearerToken); // throws if invalid/expired
```

## 3. Configure and go live

```bash
# register your real redirect URIs
curl -X PATCH $BASE/api/v1/apps/$APP_ID \
  -H "Authorization: Bearer $MASTERPACK_API_KEY" \
  -H 'content-type: application/json' \
  -d '{"redirect_uris": ["https://myapp.example/callback"]}'

# submit — automated checks, instant listing on pass
curl -X POST $BASE/api/v1/apps/$APP_ID/submit \
  -H "Authorization: Bearer $MASTERPACK_API_KEY"
```

Checks: your URL responds, redirect URIs are registered, listing text is
complete. Failures come back as a `failures` array — fix and resubmit.

## Listing images

Upload an icon and up to four screenshots from the maker dashboard
(Edit listing). Recommended:

| Image | Aspect | Size | Notes |
|-------|--------|------|-------|
| Cover | 16:9 wide | 1920×1080 or larger | store card + listing hero; cropped to 16:9 |
| Screenshot | 16:9 landscape | 1920×1080 or larger | up to 4, shown two-up in a grid |

Accepted formats: PNG, JPEG, WebP, AVIF, up to 8MB each. Everything is
resized and re-encoded to WebP on upload and served from a CDN, so upload
the highest-quality original you have.

## What your app sees about users

A stable **pairwise id** (different in every app — you cannot correlate users
across apps), a display name, and the subscription tier. Never an email.

## How you get paid

Each subscriber's monthly fee (minus the platform's 30%) is split across the
apps *they* used, weighted by active days and capped active minutes. One
sign-in isn't usage; parked tabs aren't usage. Payouts run monthly via Stripe
Connect once your balance reaches $25 — connect your Stripe account in the
maker dashboard.
