> ## Documentation Index
> Fetch the complete documentation index at: https://docs.pnta.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Client Methods

> Complete API documentation for PNTA Expo client

## Core Methods

### `createPntaClient()`

```ts theme={null}
createPntaClient(config: {
  projectId: string;
  baseUrl?: string;
})
```

Creates a PNTA client for your project.

**Parameters:**

* `projectId`: Your PNTA project ID (format: `prj_XXXXXXXXX`)
* `baseUrl` (optional): API base URL. Default: `https://app.pnta.io/api/v1`

**Returns:** a client with `identify()`, `setMetadata()`, and `onNotificationTap()`

**Throws:** if `projectId` is empty

```tsx theme={null}
const pnta = createPntaClient({ projectId: "prj_XXXXXXXXX" });
```

### `identify()`

```ts theme={null}
pnta.identify(token: string): Promise<Response>
```

Registers or updates the device for a push token. It also sends the device name, model, OS version, locale, time zone, preferred languages, bundle identifier, and app version and build, so you can target them in topic rules.

**Parameters:**

* `token`: The native APNs or FCM token from `getDevicePushTokenAsync()`

```tsx theme={null}
await pnta.identify(pushToken);
```

### `setMetadata()`

```ts theme={null}
pnta.setMetadata(token: string, metadata: Record<string, unknown>): Promise<Response>
```

Updates device metadata. Keys with `null` or `undefined` values are skipped.

**Parameters:**

* `token`: The device's push token
* `metadata`: Key-value pairs

```tsx theme={null}
await pnta.setMetadata(pushToken, { user_id: "user_123" });
```

### `onNotificationTap()`

```ts theme={null}
pnta.onNotificationTap(callback: (payload: Record<string, any>) => void): Notifications.EventSubscription
```

Tracks a notification open and calls `callback` with the notification payload on every tap, including the tap that launches the app. The SDK reads the payload from the correct place on each platform.

**Parameters:**

* `callback`: Called with the [notification payload](#notification-payload) after each tap

**Returns:** a subscription. Call `subscription.remove()` to stop listening, for example in a `useEffect` cleanup.

```tsx theme={null}
pnta.onNotificationTap((payload) => {
  if (payload.link_to) router.push(payload.link_to);
});
```

## Errors

`identify()` and `setMetadata()` reject with an `Error` when the request fails. The message includes the status code and path, for example `PNTA 404 /identification: ...`. If `onNotificationTap()` cannot record an open, it logs a warning and does not throw.

## Notification Payload

Every PNTA notification includes these fields. `onNotificationTap()` gives them to your callback:

* `notification_id`: The notification's ID
* `token`: The device's push token
* `link_to`: The link you set when sending, if any

## Link Handling

The SDK doesn't open links. Your `onNotificationTap()` callback gets `link_to` and decides what to do. With Expo Router, `router.push(payload.link_to)` handles both kinds of links:

* **Internal routes** (without a scheme) → Navigate in your app
  * Examples: `/profile`, `/settings`, `/orders/123`
  * The route must exist in your `app/` directory
* **External URLs** (with a scheme) → Open in the system browser or app
  * Examples: `https://example.com`, `mailto:test@example.com`, `tel:+1234567890`

Without Expo Router, use your navigation library for internal routes and `Linking.openURL()` from `react-native` for external URLs.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.