# Install Cyccle

This is the official machine-readable installation contract for Cyccle's v1 cancellation-flow runtime.

Canonical human guide: https://docs.cyccle.co/installation
API origin: https://api.cyccle.co/v1
Runtime script: https://flow.cyccle.co/v1/cyccle.js

## Stop conditions

- Stop if no Cyccle workspace API key has been issued. Never invent a credential.
- Stop if the exact application origin has not been registered for the workspace.
- Stop if the existing cancellation path cannot be identified and preserved as a fallback.
- Never expose the workspace API key, provider identifiers, or launch tokens in URLs or browser bundles.

## Required implementation

1. Inspect the repository's framework, authentication, subscription model, billing integration, Content Security Policy, and existing cancellation entry point before editing.
2. Add the asynchronous v1 loader after the application becomes interactive: https://flow.cyccle.co/v1/cyccle.js. Do not call open until the loader is ready; use the framework's load callback when a launch can race the download.
3. On the merchant server, exchange the private workspace API key for a fresh launch token with POST https://api.cyccle.co/v1/session-tokens.
4. Send customerId, the exact subscriptionId when known, stripeMode, and the registered canonical application origin. Tokens must expire within 15 minutes.
5. Return only the opaque token and branding object to the signed-in browser. Authorize that browser request against the current customer and subscription.
6. Call window.cyccle.open with launchToken, branding, lifecycle callbacks, and a native cancellation fallback.
7. Extend the existing CSP with exact https://flow.cyccle.co script-src, style-src, and frame-src entries. Do not use wildcard sources or unsafe-inline for Cyccle.
8. Implement and verify in test mode before live mode. Browser callbacks are notifications; billing state remains server-authoritative.

## Session-token request

```ts
const response = await fetch("https://api.cyccle.co/v1/session-tokens", {
    method: "POST",
    headers: {
        Authorization: `Bearer ${process.env.CYCCLE_API_KEY}`,
        "Content-Type": "application/json",
    },
    body: JSON.stringify({
        customerId,
        subscriptionId,
        stripeMode: "test",
        origin: process.env.CYCCLE_APP_ORIGIN,
    }),
    cache: "no-store",
});

const { token: launchToken, branding } = await response.json();
```

## Browser open call

```ts
await window.cyccle.open({
    launchToken,
    branding,
    onComplete() {
        // Refresh billing state from your server.
    },
    onError() {
        // Restore the native, subscription-scoped cancellation path.
    },
});
```

## Completion report

Run the repository's relevant tests, lint, type checks, and production build. Report changed files, verification results, the registered origin, and manual deployment steps. Never print or commit secret values.
