# API reference

URL: https://supapulse.app/docs/core/api-reference

Every method and type @supapulse/core exports, with signatures and behavior.

```ts
import { Supapulse } from '@supapulse/core';
```

The package exports the `Supapulse` class and its types. The script tag build exposes one instance as `window.supapulse`.

## new Supapulse() [#new-supapulse]

```ts
const supapulse = new Supapulse();
```

Creates a tracker and its session ID. Nothing is sent until `init()`.

## init() [#init]

```ts
init(config: SupapulseConfig): void
```

Starts the tracker. Sets up automatic pageviews (unless `autoPageviews: false`) and the handlers that flush pending sends when the page is hidden or closed.

- Throws `Browser environment required` if `window` is undefined.
- A second call on the same instance is ignored.

See [Configuration](https://supapulse.app/docs/core/configuration) for the options.

## pageview() [#pageview]

```ts
pageview(options?: PageviewOptions): Promise<void>
```

Sends a pageview. Defaults to `location.href`, `document.referrer` and `document.title`. The promise resolves once the request is handed off, not when the server has stored it.

## event() [#event]

```ts
event(eventName: string, eventData?: EventData): Promise<void>
```

Sends a custom event with optional properties. Does nothing if `eventName` is empty.

## getSessionId() [#getsessionid]

```ts
getSessionId(): string
```

Returns the session ID: a random UUID created with the tracker. Pass it to your server at checkout to link a payment to this visit. See [Sessions](https://supapulse.app/docs/core/sessions).

## identify() [#identify]

```ts
identify(customerId: string): Promise<void>
```

Links the current visitor to your own customer ID, so revenue sent later for that ID is credited to the visitor's first touch. Call it after login or signup. It sends `{ customer_id, session_id, url }` as an `identify` event with the public token. Supapulse builds the visitor fingerprint on the server from the request. Does nothing if `customerId` is empty or the tracker isn't initialized. Identify events never count toward your usage.

```ts
supapulse.identify(user.id);
```

See [Revenue attribution](https://supapulse.app/docs/revenue/attribution).

## getVisitorFingerprint() [#getvisitorfingerprint]

```ts
getVisitorFingerprint(): Promise<string | null>
```

Resolves to the visitor's fingerprint, the same server-built hash stored on their pageviews. The first call requests it from `POST /api/fingerprint` with the public token. The result is cached on the instance, and concurrent calls share one request. Pass it through checkout metadata for the strongest revenue link.

Resolves to `null` and sends nothing if the tracker isn't initialized. It also resolves to `null` when the request fails. A network error or a `5xx` isn't cached, so the next call tries again. A `401`, `402`, `403` or `404` is final: the `null` is cached and the instance doesn't ask again.

```ts
const fingerprint = await supapulse.getVisitorFingerprint(); // string | null
```

The endpoint comes from `fingerprintEndpoint`, which defaults to `endpoint` with `/ingest` replaced by `/fingerprint`. For a custom endpoint that doesn't end in `/ingest`, it uses `/api/fingerprint` on the endpoint's origin.

## Retries and final status codes [#retries-and-final-status-codes]

Sends use `sendBeacon` first and fall back to `fetch`. On a failed `fetch`:

| Response | What the tracker does |
| --- | --- |
| `2xx` | Done. |
| `429` | Waits for `Retry-After` (60 seconds if missing), then retries. |
| `400`, `401`, `402`, `403`, `404`, `413`, `422` | Final. The event is dropped without retrying. |
| Anything else, or a network error | Retries with exponential backoff, up to `maxRetries`, then drops it. |

A `402` means the site's team has no active plan or reached its monthly event limit. See [Error codes](https://supapulse.app/docs/api/errors#402-responses).

## use() [#use]

```ts
use(extension: SupapulseExtension): void
```

Registers an extension and calls its `init(core)` with the tracker. Registering the same `name` twice is ignored.

```ts
supapulse.use({
  name: 'scroll-depth',
  init(core) {
    let sent = false;
    addEventListener('scroll', () => {
      const depth = (scrollY + innerHeight) / document.body.scrollHeight;
      if (!sent && depth > 0.9) {
        sent = true;
        core.event('scrolled_to_bottom');
      }
    });
  },
});
```

## Types [#types]

```ts
interface SupapulseConfig {
  apiToken: string;
  endpoint?: string;
  fingerprintEndpoint?: string;
  autoPageviews?: boolean;
  debug?: boolean;
  maxRetries?: number;
  retryBackoff?: number;
}

interface PageviewOptions {
  url?: string;
  referrer?: string;
  title?: string;
}

interface EventData {
  [key: string]: any;
}

interface SupapulseExtension {
  name: string;
  init(core: SupapulseCore): void;
}

interface SupapulseCore {
  init(config: SupapulseConfig): void;
  pageview(options?: PageviewOptions): void;
  event(eventName: string, eventData?: EventData): void;
  identify(customerId: string): Promise<void>;
  getVisitorFingerprint(): Promise<string | null>;
  getSessionId(): string;
  use(extension: SupapulseExtension): void;
}
```

`TrackingData` and `QueuedEvent` describe the request payload and the retry queue. They're exported for completeness; you don't need them to use the tracker. The full list is in [TypeScript types](https://supapulse.app/docs/api/types).

## Not in the API [#not-in-the-api]

Older docs mentioned `reset()`, `isInitialized()`, `isIdentified()` and a `supapulse.q` command queue. None of them exist.

## Browser support [#browser-support]

The tracker needs `fetch`, `Blob`, `URL` and `history.pushState`, which every current browser has. It uses `crypto.randomUUID()` when available and falls back to `Math.random()` for session IDs.
