# Connect Stripe to Analytiics

Connect Stripe in project settings to import payments, partial refunds and
subscription renewals. No webhook or SDK revenue code is needed. Imported Stripe
events do not count toward the monthly event cap.

## Connect a restricted key

1. Open your project's **Settings → Stripe revenue** and click
   **Create restricted key in Stripe**, or [open the prefilled Stripe form](https://dashboard.stripe.com/apikeys/create?name=Analytiics&thirdparty_integration_name=Analytiics&thirdparty_integration_url=https%3A%2F%2Fwww.analytiics.co&permissions%5B0%5D=rak_charge_read&permissions%5B1%5D=rak_customer_read&permissions%5B2%5D=rak_event_read&permissions%5B3%5D=rak_dispute_read&permissions%5B4%5D=rak_invoice_read&permissions%5B5%5D=rak_subscription_read&permissions%5B6%5D=rak_bucket_checkout_read).
2. Choose the correct Stripe account or sandbox. The key is named **Analytiics**
   and its read permissions are already selected. Review them, then click
   **Create key** and complete any verification Stripe requests.
3. Copy the `rk_live_…` or `rk_test_…` key and paste it into Analytiics settings.
   Click **Connect Stripe**.

Required permissions: Charges and Refunds, Customers, Events, Payment Disputes, Invoices (including invoice payments), Subscriptions, and Checkout Sessions — all Read; everything else, including Connect permissions, None.
The link only prepares the form; Stripe creates the key when you confirm.
If the shortcut does not prefill the form, open
[Stripe API keys](https://dashboard.stripe.com/apikeys), choose **Create restricted key**,
name it **Analytiics**, and select the permissions above.

Full `sk_…` secret keys are refused. Keys are encrypted on the server and never
returned by the API; settings shows only the mode and last four characters.

The first scheduled sync starts the import. It checks up to 90 days of charges,
in pages, with a 5,000-charge limit. Current payments continue syncing during
backfill. Settings shows progress, the last successful sync, imported payments,
and error categories. Hosted sync is scheduled every five minutes, subject to
deployment configuration. Large imports take multiple runs.

Test keys import test data. Use a separate Analytiics project to verify test
payments before connecting your live project. Disconnecting stops future
imports and deletes the stored key; existing analytics remain. Reconnecting
the same account reuses stable payment IDs rather than counting them again.
Do not send SDK revenue for payments already imported by this integration.

## Credit the channel that brought the customer

Payments count even without attribution, under **Unattributed**. To connect them
to a customer's first visit, identify the user after signup and login:

```ts
window.analytiics?.identify(user.id);
```

Use that same opaque user ID in server-side Checkout creation:

```ts
const session = await stripe.checkout.sessions.create({
  mode: "subscription",
  line_items: [{ price: priceId, quantity: 1 }],
  client_reference_id: user.id,
  subscription_data: {
    metadata: { analytiics_user_id: user.id },
  },
  success_url: successUrl,
  cancel_url: cancelUrl,
});
```

For one-time Checkout, omit `subscription_data`. Checkout metadata
`analytiics_user_id`, subscription metadata, and customer metadata also resolve
user IDs. `client_reference_id` has priority: do not put an order ID there when
you expect user attribution. Renewals reuse the saved customer-to-user mapping.
Never use an email address or name as the ID.

For a checkout without sign-in, read `window.analytiics?.session()` in the
browser, pass it through your checkout request, and merge it into the Checkout
Session's `metadata.analytiics_session_id`. This read-only getter returns the
current session ID without extending its life. An empty ID means attribution
is unavailable. Session metadata credits that session's entry source directly;
it does not link later purchases from the same customer.

Declare the integration in your tracking plan:

```yaml
version: 1
project: your-domain.com
integrations: [stripe]
events: {}
```

Run `analytiics push`. `analytiics check` warns if a signed-in project's
connection and manifest disagree. Install `revenue-wire-up` with
`analytiics skills install revenue-wire-up` for an agent to make these edits.

## Verify and read revenue

`analytiics integrations stripe status` reads the owner-only status endpoint.
`payments_30d` counts confirmed deliveries; `linked_30d` counts those carrying a
user or session ID. `attributed_30d` and `latest_source` verify the source join
in analytics. Null means analytics verification was unavailable. Imported rows
can take another dashboard cache refresh to appear.

The dashboard shows net revenue per currency, its previous-period comparison,
new revenue and renewals by source, and an owner-only list of the latest 100
payments in the selected period. Source and channel filters apply. Browser,
page and device filters do not narrow revenue. The existing public Revenue
switch controls the revenue KPI and source card; payment-level user IDs remain
private even when Revenue is published.

Refunds use their original dates and lower net revenue. Dispute withdrawals
lower it and returned dispute funds restore it. Amounts stay separate by
currency. The analytics contract stores hundredths: fractional hundredths in
three-decimal currencies pause sync with `unsupported_currency` rather than
being rounded. If sync falls behind Stripe's event retention, `history_gap`
requires attention; it does not silently claim a complete import.

For Paddle, Polar, Lemon Squeezy or custom billing, use the
[server SDK revenue guide](/docs/sdk). Those manifest-declared events continue
to work independently.
