# List Devices Source: https://docs.pnta.io/api-reference/devices/list-devices https://app.pnta.io/api-docs/v1/swagger.json get /api/v1/devices Returns a paginated list of devices for the current project # Introduction Source: https://docs.pnta.io/api-reference/introduction Getting started with the PNTA API ## Welcome to the PNTA API The PNTA API provides a comprehensive set of endpoints to manage your application data programmatically. Our REST API is designed to be simple, predictable, and resource-oriented. ## Base URL All API requests should be made to: ``` https://app.pnta.io/api/v1 ``` ## Authentication All API endpoints require authentication using API keys. Include your API key in the Authorization header: ```bash theme={null} Authorization: Bearer YOUR_API_KEY ``` You can manage your API keys from the [PNTA dashboard](https://app.pnta.io). ## Response Format All API responses are returned in JSON format. Successful responses will have a 2xx status code, while errors will return appropriate 4xx or 5xx status codes with detailed error messages. ## Response Codes PNTA uses standard HTTP codes to indicate the success or failure of your requests. In general, 2xx HTTP codes correspond to success, 4xx codes are for user-related failures, and 5xx codes are for infrastructure issues. | Status | Description | | - | - | | `200` | Successful request. | | `201` | Resource created successfully. | | `400` | Bad request - check that the parameters were correct. | | `401` | Unauthorized - the API key used was missing or invalid. | | `404` | The resource was not found. | | `422` | Unprocessable entity - validation errors in request data. | | `5xx` | Indicates an error with PNTA servers. | # Update Device Metadata Source: https://docs.pnta.io/api-reference/metadata/update-device-metadata https://app.pnta.io/api-docs/v1/swagger.json patch /api/v1/metadata Updates device metadata # Send Notification Source: https://docs.pnta.io/api-reference/notifications/send-notification https://app.pnta.io/api-docs/v1/swagger.json post /api/v1/notifications Send a notification to the specified targets # Track Notification Open Source: https://docs.pnta.io/api-reference/notifications/track-notification-open https://app.pnta.io/api-docs/v1/swagger.json put /api/v1/notifications/{id}/open Record that a device opened the notification. Unauthenticated; the device echoes back the token from the notification payload. # List Topics Source: https://docs.pnta.io/api-reference/topics/list-topics https://app.pnta.io/api-docs/v1/swagger.json get /api/v1/topics Returns a paginated list of topics for the current project # Plugin Methods Source: https://docs.pnta.io/guides/flutter/api-reference Complete API documentation for PNTA Flutter plugin ## Core Methods ### `initialize()` ```dart theme={null} PntaFlutter.initialize(String projectId, { Map? metadata, bool registerDevice = true, bool autoHandleLinks = false, bool showSystemUI = false, }) ``` Initializes the plugin and optionally registers the device. When `registerDevice: true` (default), this method will prompt the user for notification permission and register the device with PNTA. Use `registerDevice: false` for delayed registration if you don't want to prompt the user immediately. **Parameters:** * `projectId`: Your PNTA project ID (format: `prj_XXXXXXXXX`) * `metadata` (optional): Device metadata as key-value pairs * `registerDevice` (optional): Whether to register device immediately. Default: `true` * `autoHandleLinks` (optional): Automatically handle `link_to` URLs when notifications are tapped from background/terminated state. Default: `false` * `showSystemUI` (optional): Show system notification banner/sound when app is in foreground. Default: `false` **Returns:** `Future` **Examples:** ```dart lib/main.dart theme={null} // Minimal - handles everything automatically await PntaFlutter.initialize('prj_XXXXXXXXX'); // With metadata and configuration await PntaFlutter.initialize( 'prj_XXXXXXXXX', metadata: { 'user_id': '123', 'user_email': 'user@example.com', }, autoHandleLinks: true, // Optional: enable auto-handling of links showSystemUI: true, // Optional: show system UI in foreground ); // Delayed registration scenario await PntaFlutter.initialize( 'prj_XXXXXXXXX', metadata: { 'user_id': '123', 'user_email': 'user@example.com', }, registerDevice: false, // Don't register immediately autoHandleLinks: true, ); // Register later with registerDevice() ``` ### `registerDevice()` ```dart theme={null} PntaFlutter.registerDevice() ``` Registers the device with your PNTA project using metadata from `initialize()`. Only needed when using delayed registration (when `initialize()` was called with `registerDevice: false`). **Returns:** `Future` **Example:** ```dart lib/main.dart theme={null} // First initialize with metadata but don't register await PntaFlutter.initialize( 'prj_XXXXXXXXX', metadata: { 'user_id': '123', 'user_email': 'user@example.com', }, registerDevice: false, ); // Later, register when ready (uses stored metadata) await PntaFlutter.registerDevice(); // Get device token after registration final token = PntaFlutter.deviceToken; if (token != null) { print('Device registered with token: $token'); } ``` Must call `initialize()` first. Only use this method when you initialized with `registerDevice: false`. ### `updateMetadata()` ```dart theme={null} PntaFlutter.updateMetadata(Map metadata) ``` Updates device metadata without re-registering. **Parameters:** * `metadata`: Updated metadata as key-value pairs **Returns:** `Future` **Example:** ```dart lib/main.dart theme={null} await PntaFlutter.updateMetadata({ 'last_active': DateTime.now().toIso8601String(), }); ``` ### `handleLink()` ```dart theme={null} PntaFlutter.handleLink(String link) ``` Manually handles a link using the plugin's routing logic. **Parameters:** * `link`: The link to handle **Returns:** `void` **Example:** ```dart lib/main.dart theme={null} PntaFlutter.handleLink('/profile'); PntaFlutter.handleLink('https://example.com'); ``` ## Properties ### `deviceToken` ```dart theme={null} PntaFlutter.deviceToken ``` Gets the current device token after successful initialization or registration. **Type:** `String?` **Returns:** Device token string if registration was successful, `null` otherwise. **Example:** ```dart lib/main.dart theme={null} await PntaFlutter.initialize('prj_XXXXXXXXX'); final token = PntaFlutter.deviceToken; if (token != null) { print('Device token: $token'); } else { print('Device registration failed or not completed'); } ``` ### `navigatorKey` ```dart theme={null} PntaFlutter.navigatorKey ``` Global navigator key for internal route navigation. Must be assigned to your `MaterialApp`. **Type:** `GlobalKey` **Example:** ```dart lib/main.dart theme={null} MaterialApp( navigatorKey: PntaFlutter.navigatorKey, // ... rest of your app ) ``` ### `foregroundNotifications` ```dart theme={null} PntaFlutter.foregroundNotifications ``` Stream of notification payloads received when app is in foreground. **Type:** `Stream>` **Payload Structure:** Both iOS and Android send identical flat payload structures: ```json theme={null} { "title": "Rain expected this afternoon", "body": "Showers from 2–5 PM in your area...", "link_to": "https://example.com/weather", "custom_field": "custom_value" } ``` **Example:** ```dart lib/main.dart theme={null} PntaFlutter.foregroundNotifications.listen((payload) { final title = payload['title']; final body = payload['body']; final link = payload['link_to']; print('Received: $title'); // Show custom UI ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('$title: $body')), ); }); ``` ### `onNotificationTap` ```dart theme={null} PntaFlutter.onNotificationTap ``` Stream of notification payloads when user taps a notification from background/terminated state. **Type:** `Stream>` **Payload Structure:** Contains the `link_to` field and any custom data fields. System fields (`title`, `body`) are not available on Android due to platform limitations. ```json theme={null} { "link_to": "https://example.com/weather" } ``` **Example:** ```dart lib/main.dart theme={null} PntaFlutter.onNotificationTap.listen((payload) { print('User tapped notification: $payload'); // Access link_to field (available on both platforms) final linkTo = payload['link_to'] as String?; // Track analytics, navigate to specific screen, etc. }); ``` ## Link Handling The plugin handles notification links automatically using smart URL detection: * **External URLs** (with scheme) → Opens in system browser/apps * Examples: `https://example.com`, `mailto:test@example.com`, `tel:+1234567890`, `sms:+1234567890` * Works automatically with no additional configuration required * **Internal routes** (without scheme) → Navigates using Flutter's Navigator * Examples: `/profile`, `/settings`, `/dashboard` * Requires `navigatorKey` setup (covered in Quick Start) ## Implementing Notification Listeners ### App-Level Global listeners in `main.dart`. No disposal needed since the app doesn't get disposed. ```dart theme={null} void main() async { await PntaFlutter.initialize('prj_XXXXXXXXX'); PntaFlutter.foregroundNotifications.listen((payload) { print('Got notification: ${payload['title']}'); }); runApp(MyApp()); } ``` ### Widget-Level Listeners in StatefulWidgets. Disposal required to prevent memory leaks. ```dart theme={null} class HomePage extends StatefulWidget { @override _HomePageState createState() => _HomePageState(); } class _HomePageState extends State { StreamSubscription? _sub; @override void initState() { super.initState(); _sub = PntaFlutter.foregroundNotifications.listen((payload) { // Handle notification }); } @override void dispose() { _sub?.cancel(); // Required to prevent memory leaks super.dispose(); } } ``` # Introduction Source: https://docs.pnta.io/guides/flutter/index A Flutter plugin for requesting push notification permissions and handling notifications on iOS and Android with deep linking support. ## Requirements * iOS 12.0+ * Android API 21+ * Flutter 3.3.0+ ## Get Started Configure iOS and Android Get up and running in minutes Complete plugin API documentation Common issues and solutions ## Installation Visit [pub.dev](https://pub.dev/packages/pnta_flutter) to see the latest package details, then add the plugin: ```bash theme={null} flutter pub add pnta_flutter ``` Import it in your project: ```dart lib/main.dart theme={null} import 'package:pnta_flutter/pnta_flutter.dart'; ``` ## Resources Install from pub.dev View source code and contribute # Platform Setup Source: https://docs.pnta.io/guides/flutter/platform-setup Configure iOS and Android platforms for push notifications with PNTA Flutter plugin ## iOS Setup ### 1. Xcode Configuration 1. Open `ios/Runner.xcworkspace` in Xcode 2. Select your app target and go to "Signing & Capabilities" 3. Add "Push Notifications" capability 4. Add "Background Modes" capability and enable "Remote notifications" Your `ios/Runner/Info.plist` should include: ```xml ios/Runner/Info.plist theme={null} UIBackgroundModes remote-notification ``` ### 2. Plugin Integration **Automatic!** The plugin integrates automatically when you run: ```bash theme={null} flutter pub get cd ios && pod install ``` **No manual Podfile configuration needed** - Flutter generates the standard Podfile automatically. ## Android Setup ### 1. Firebase Configuration 1. Go to the [Firebase Console](https://console.firebase.google.com/) 2. Create a new project or select an existing one 3. Register your Android app using your package name (e.g., `com.example.your_app`) 4. Download `google-services.json` and place it at `android/app/google-services.json` ### 2. Gradle Configuration **Project-level `android/build.gradle`:** Add to the `buildscript { dependencies { ... } }` block: ```gradle android/build.gradle theme={null} classpath 'com.google.gms:google-services:4.3.15' // or latest version ``` **App-level `android/app/build.gradle`:** Add at the very bottom: ```gradle android/app/build.gradle theme={null} apply plugin: 'com.google.gms.google-services' ``` # Quick Start Source: https://docs.pnta.io/guides/flutter/quick-start Get up and running with PNTA Flutter plugin in minutes ## Prerequisites Make sure you've completed the [Platform Setup](/guides/flutter/platform-setup) for iOS and Android before proceeding. ## How to Use Add one line to your app's `main()` function: ```dart lib/main.dart theme={null} import 'package:pnta_flutter/pnta_flutter.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // That's it! Handles permissions and registration automatically await PntaFlutter.initialize('prj_XXXXXXXXX'); runApp(MyApp()); } ``` Get your project ID from your [PNTA Dashboard](https://app.pnta.io) settings. **That's it!** Your app now receives push notifications. *** ## Advanced Usage ### Configuration Options You can configure optional parameters for more control: ```dart lib/main.dart theme={null} await PntaFlutter.initialize( 'prj_XXXXXXXXX', metadata: { 'user_id': '123', 'user_email': 'user@example.com', }, registerDevice: false, // Optional: delay registration until later autoHandleLinks: true, // Optional: enable auto-handling of links showSystemUI: true, // Optional: show system UI when app is in foreground ); // Get device token after initialization/registration final deviceToken = PntaFlutter.deviceToken; if (deviceToken != null) { print('Device registered: $deviceToken'); } ``` ### Delayed Registration If you need to register the device later (e.g., after user login), use delayed registration: ```dart lib/main.dart theme={null} void main() async { WidgetsFlutterBinding.ensureInitialized(); // Initialize with metadata but don't register yet await PntaFlutter.initialize( 'prj_XXXXXXXXX', metadata: { 'user_id': '123', 'user_email': 'user@example.com', }, registerDevice: false, // Don't register immediately ); runApp(MyApp()); } void _registerAfterLogin() async { // Register device (uses metadata from initialize) await PntaFlutter.registerDevice(); } ``` **Best Practice:** Consider delayed registration for better opt-in rates. Prompt users for notifications during onboarding or after signup when they understand the value. ### Custom Notification Handling #### Foreground Notifications When your app is open and active, notifications arrive silently by default (no system banner). Use this to show custom UI like snackbars or dialogs: ```dart lib/main.dart theme={null} PntaFlutter.foregroundNotifications.listen((payload) { print('Received foreground notification: ${payload['title']}'); // Show custom UI (snackbar, dialog, etc.) ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text('${payload['title']}: ${payload['body']}')), ); // Manually handle links if needed final link = payload['link_to'] as String?; if (link != null && link.isNotEmpty) { PntaFlutter.handleLink(link); } }); ``` **iOS**: Set `showSystemUI: true` to display the standard notification banner when your app is in the foreground. **Android**: Set `showSystemUI: true` to make notifications appear in the notification panel. By default, Android foreground notifications are silent and don't appear in the panel. You'll need to handle in-app UI using the listener above. #### Background/Terminated Notifications When users tap notifications while your app is in background or closed: ```dart lib/main.dart theme={null} PntaFlutter.onNotificationTap.listen((payload) { print('User tapped notification: $payload'); // Access link_to field (available on both platforms) final linkTo = payload['link_to'] as String?; // Track analytics, show specific screen, etc. // Links are auto-handled if autoHandleLinks is set to true }); ``` Set `autoHandleLinks: true` to automatically handle notification links. External URLs open in the browser, internal routes navigate within your app (requires navigator key setup). ### Deep Linking Setup For notifications that navigate to specific pages in your app: ```dart lib/main.dart theme={null} MaterialApp( navigatorKey: PntaFlutter.navigatorKey, // Required for internal route navigation // ... rest of your app ) ``` Only needed if your notifications contain internal routes like `/profile`. External URLs with schemes (`https://`, `mailto:`, `tel:`, `sms:`) work automatically with no configuration. ### Complete Example This example shows multiple optional features. Remember: most apps only need the one-liner from "How to Use" above. ```dart lib/main.dart theme={null} import 'package:flutter/material.dart'; import 'package:pnta_flutter/pnta_flutter.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); // Initialize plugin - handles everything automatically await PntaFlutter.initialize( 'prj_XXXXXXXXX', metadata: { 'user_id': '123', 'user_email': 'user@example.com', }, autoHandleLinks: true, // Optional: enable auto-handling of links ); // App-level listeners - work everywhere, no disposal needed PntaFlutter.foregroundNotifications.listen((payload) { print('Foreground notification: ${payload['title']}'); }); PntaFlutter.onNotificationTap.listen((payload) { print('Notification tapped: ${payload['link_to']}'); }); runApp(MyApp()); } class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( navigatorKey: PntaFlutter.navigatorKey, // Required for deep linking home: HomePage(), ); } } class HomePage extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar(title: Text('PNTA Example')), body: Center(child: Text('Ready for notifications!')), ); } } ``` # Troubleshooting Source: https://docs.pnta.io/guides/flutter/troubleshooting Common issues and solutions for PNTA Flutter plugin ## Device Registration Issues ### Device registration fails **Symptoms:** `PntaFlutter.deviceToken` returns `null` after initialization **Common causes:** * **Permission denied**: User declined notification permission * **Invalid project ID**: Project ID doesn't start with `prj_` or is incorrect * **Platform setup incomplete**: Missing Firebase configuration (Android) or iOS capabilities * **Network issues**: Device can't connect to registration servers **Solutions:** * Verify project ID format: `prj_XXXXXXXXX` * Test on physical devices (emulators may have permission issues) * Check platform setup is complete (see Platform Setup guide) * Retry registration after fixing setup issues * Check device token using `PntaFlutter.deviceToken` getter after initialization ### Delayed registration issues **Symptoms:** `registerDevice()` fails after `initialize(registerDevice: false)` **Solutions:** * Ensure `initialize()` was called first * Check that platform setup is complete before calling `registerDevice()` * Verify user hasn't manually disabled notifications in system settings ## Firebase Configuration Issues ### Firebase setup problems **Symptoms:** Build errors, FCM token not generated, notifications not received **Solutions:** * Verify `google-services.json` is in the correct location: `android/app/google-services.json` * Check that Firebase project is properly configured with your app's package name * Ensure Google Services plugin is applied in the correct build.gradle files * Verify classpath is added to project-level build.gradle **Project-level `android/build.gradle`:** ```gradle android/build.gradle theme={null} buildscript { dependencies { classpath 'com.google.gms:google-services:4.3.15' } } ``` **App-level `android/app/build.gradle`:** ```gradle android/app/build.gradle theme={null} // At the very bottom apply plugin: 'com.google.gms.google-services' ``` ## Link Handling Issues ### Internal routes not working **Symptoms:** App opens but doesn't navigate to internal pages like `/profile`, `/settings` **Solutions:** * Verify `navigatorKey` is assigned to MaterialApp (see Quick Start guide) * Check that routes are properly defined in your app * Ensure `autoHandleLinks: true` is set in initialize() if you want automatic link handling ## Notification Delivery Issues ### Notifications not received **Symptoms:** Device registration successful but notifications don't arrive **Solutions:** * Verify device registration was successful: check `PntaFlutter.deviceToken` is not `null` * Check PNTA project is configured correctly in dashboard * Ensure Firebase setup is complete (Android) * Test with a simple notification from PNTA dashboard * Verify app is in background/terminated when testing (foreground notifications need custom handling) * Check device notification settings haven't been disabled by user ## Setup and Configuration Issues ### Plugin initialization problems **Symptoms:** `initialize()` throws errors or app crashes **Solutions:** * Call `WidgetsFlutterBinding.ensureInitialized()` before `initialize()` * Ensure `initialize()` is awaited properly * Verify project ID format is correct (`prj_XXXXXXXXX`) * Check platform setup is complete before calling `initialize()` * If using delayed registration, don't call other methods until after `registerDevice()` ## Getting Help If you're still experiencing issues: 1. Check the [example app](https://github.com/pnta-io/pnta-flutter-plugin/tree/main/example) for a complete working implementation 2. Review your implementation against the [Quick Start Guide](/guides/flutter/quick-start) 3. Verify platform setup following the [Platform Setup Guide](/guides/flutter/platform-setup) 4. File an issue on the [GitHub repository](https://github.com/pnta-io/pnta-flutter-plugin/issues) with: * Flutter version (`flutter --version`) * Plugin version * Platform (iOS/Android) * Detailed error messages * Minimal reproduction code # Introduction Source: https://docs.pnta.io/guides/kotlin/index Get started with PNTA in your Android app The Kotlin Android SDK is coming soon. Documentation will be available once released. ## Coming Soon PNTA Kotlin Android SDK is currently in development. Stay tuned for updates! # Client Methods Source: https://docs.pnta.io/guides/react-native/api-reference 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 ``` 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): Promise ``` 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) => 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. # Introduction Source: https://docs.pnta.io/guides/react-native/index An Expo client for registering push tokens and tracking notification opens with PNTA on iOS and Android. ## Requirements * Expo SDK 54+ ## Get Started Configure iOS and Android Get up and running in minutes Complete client API documentation Common issues and solutions ## Installation Visit [npm](https://www.npmjs.com/package/@pnta/expo) to see the latest package details, then add the client: ```bash theme={null} npx expo install @pnta/expo ``` Import it in your project: ```tsx app/_layout.tsx theme={null} import { createPntaClient } from "@pnta/expo"; ``` ## Resources Install from npm View source code and contribute # Platform Setup Source: https://docs.pnta.io/guides/react-native/platform-setup Configure iOS and Android platforms for push notifications with PNTA Expo client ## Config Plugin Add the `expo-notifications` config plugin to `app.json`. It adds the iOS push capability and the Android notification setup at build time: ```json app.json theme={null} { "expo": { "plugins": ["expo-notifications"] } } ``` ## iOS Setup Set your bundle identifier in `app.json`: ```json app.json theme={null} { "expo": { "ios": { "bundleIdentifier": "com.example.yourapp" } } } ``` Upload your APNs key in the PNTA dashboard. See [Platform Keys](/resources/platform-keys). ## Android Setup ### 1. Firebase Configuration 1. Go to the [Firebase Console](https://console.firebase.google.com/) 2. Create a new project or select an existing one 3. Register your Android app using your package name (e.g., `com.example.yourapp`) 4. Download `google-services.json` and place it in your project root ### 2. App Configuration ```json app.json theme={null} { "expo": { "android": { "package": "com.example.yourapp", "googleServicesFile": "./google-services.json" } } } ``` Upload your Firebase service account in the PNTA dashboard. See [Platform Keys](/resources/platform-keys). ## Build Push notifications need a development build. Expo Go doesn't support them: ```bash theme={null} npx expo run:ios npx expo run:android ``` Or build with EAS: ```bash theme={null} eas build --profile development ``` # Quick Start Source: https://docs.pnta.io/guides/react-native/quick-start Get up and running with PNTA Expo client in minutes ## Prerequisites Make sure you've completed the [Platform Setup](/guides/react-native/platform-setup) for iOS and Android before proceeding. ## How to Use Create a client, request permission, identify the device's push token, and handle notification taps: ```tsx app/_layout.tsx theme={null} import { useEffect } from "react"; import { Platform } from "react-native"; import { router, Stack } from "expo-router"; import * as Notifications from "expo-notifications"; import { createPntaClient } from "@pnta/expo"; // Handle notifications that arrive while the app is in the foreground. Notifications.setNotificationHandler({ handleNotification: async () => ({ shouldShowBanner: true, shouldShowList: true, shouldPlaySound: true, shouldSetBadge: true, }), }); const pnta = createPntaClient({ projectId: "prj_XXXXXXXXX" }); export default function RootLayout() { useEffect(() => { // Identify current push token with PNTA. registerForPushNotificationsAsync().then((token) => token && pnta.identify(token)); // Push tokens can rotate; re-identify when that happens. const subscription = Notifications.addPushTokenListener((token) => pnta.identify(token.data), ); // Track notification opens on tap. const tapSubscription = pnta.onNotificationTap((payload) => { // Deep link to the notification's link_to, if it has one. if (payload.link_to) router.push(payload.link_to); }); return () => { subscription.remove(); tapSubscription.remove(); }; }, []); return ; } // Prompts for notification permission. async function registerForPushNotificationsAsync() { if (Platform.OS === "android") { await Notifications.setNotificationChannelAsync("default", { name: "default", importance: Notifications.AndroidImportance.MAX, vibrationPattern: [0, 250, 250, 250], lightColor: "#FF231F7C", }); } const { status: existingStatus } = await Notifications.getPermissionsAsync(); let finalStatus = existingStatus; if (existingStatus !== "granted") { const { status } = await Notifications.requestPermissionsAsync(); finalStatus = status; } if (finalStatus !== "granted") return; try { return (await Notifications.getDevicePushTokenAsync()).data; } catch (e) { console.warn("Failed to get push token", e); } } ``` Get your project ID from your [PNTA Dashboard](https://app.pnta.io) settings. **That's it!** Your app now receives push notifications. `getDevicePushTokenAsync()` returns the native APNs or FCM token. PNTA uses it as the device identifier. *** ## Advanced Usage ### Metadata Set custom data on the device after login. Use it to target users from the [API](/api-reference/introduction) or in topic rules: ```tsx theme={null} await pnta.setMetadata(token, { user_id: "123", user_email: "user@example.com", }); ``` ### Delayed Registration Ask for permission later, for example after signup, when users understand the value: ```tsx theme={null} async function onSignup() { const token = await registerForPushNotificationsAsync(); if (token) await pnta.identify(token); } ``` **Best Practice:** Consider delayed registration for better opt-in rates. # Troubleshooting Source: https://docs.pnta.io/guides/react-native/troubleshooting Common issues and solutions for PNTA Expo client ## Device Registration Issues ### No push token **Symptoms:** `getDevicePushTokenAsync()` throws or returns nothing **Common causes:** * **Expo Go**: Push tokens need a development build * **Emulator**: Android emulators without Google Play can't get push tokens * **Permission denied**: User declined notification permission * **Missing Firebase config**: `googleServicesFile` isn't set in `app.json` **Solutions:** * Run a development build on a physical device * Check the [Platform Setup](/guides/react-native/platform-setup) is complete * Check the permission in the device's system settings The iOS simulator gets a push token only with Xcode 14+ on a Mac with Apple silicon. ### Device doesn't appear in the dashboard **Symptoms:** `identify()` throws, or the device is missing in the PNTA dashboard **Solutions:** * Verify project ID format: `prj_XXXXXXXXX` * Check the error message: it includes the status code * Make sure you call `identify()` with the token from `getDevicePushTokenAsync()`, not `getExpoPushTokenAsync()` ## Notification Delivery Issues ### Notifications not received **Solutions:** * Check that the device appears as active in the dashboard * Check your APNs key and Firebase service account in [Platform Keys](/resources/platform-keys) * Check the delivery logs in the dashboard for the APNs or FCM response * Set a notification handler to see notifications while the app is open (see [Quick Start](/guides/react-native/quick-start#how-to-use)) ### Wrong bundle identifier or package name **Symptoms:** APNs or FCM rejects the send in the delivery logs **Solutions:** * Make sure `ios.bundleIdentifier` and `android.package` in `app.json` match the credentials you uploaded ## Link Handling Issues ### Tapping a notification doesn't open the link **Symptoms:** The app opens but doesn't navigate to `link_to` **Solutions:** * Call `pnta.onNotificationTap()` in your root component, so it also gets the tap that launched the app * Make sure the callback calls `router.push(payload.link_to)` (see [Link Handling](/guides/react-native/api-reference#link-handling)) * Check that the route exists in your `app/` directory, for example `app/profile.tsx` for `/profile` * Check the `link_to` value you set when sending the notification ## Getting Help Email [support@pnta.io](mailto:support@pnta.io) or ask in [Discord](https://discord.gg/RQ7AuS8EC9). # Introduction Source: https://docs.pnta.io/guides/swift/index Get started with PNTA in your iOS app The Swift iOS SDK is coming soon. Documentation will be available once released. ## Coming Soon PNTA Swift iOS SDK is currently in development. Stay tuned for updates! # Introduction Source: https://docs.pnta.io/index Welcome to PNTA - Push notifications made simple ## Getting Started PNTA provides native SDKs and packages for popular mobile development frameworks. Choose your platform to get started: Get started with PNTA in Flutter Get started with PNTA in React Native (Expo) Swift iOS SDK coming soon Kotlin Android SDK coming soon ## Next Steps Get up and running with PNTA in minutes Explore our comprehensive API documentation # FlutterFlow Source: https://docs.pnta.io/integrations/flutterflow Set up push notifications in your FlutterFlow project using PNTA ## Prerequisites * FlutterFlow account and project * PNTA account with project ID (`prj_XXXXXXXXX`) * For Android: Firebase project * For iOS: Apple Developer account * Platform keys configured in [PNTA Dashboard](https://app.pnta.io) (see [Platform Keys Setup](/resources/platform-keys)) ## Setup Steps ### 1. Firebase Configuration (Android Only) In FlutterFlow, set up Firebase for Android (FlutterFlow handles all the configuration automatically): 1. Go to **Settings** → **Firebase** 2. Either create a new Firebase project or connect an existing one 3. Click **Generate Config Files** 4. FlutterFlow will handle the `google-services.json` setup automatically **Do NOT enable FlutterFlow's built-in push notifications.** This setting adds FlutterFlow's own implementation that only uses FCM and requires Firebase Auth. PNTA works fully independent of this and is compatible with any auth or database you decide to use. FlutterFlow Firebase Setup ### 2. Add PNTA Dependency 1. Go to **Settings** → **Project Dependencies** 2. Click **Add Pub Dependency** 3. Visit [pub.dev/packages/pnta\_flutter](https://pub.dev/packages/pnta_flutter) 4. Copy the latest version and paste it into FlutterFlow FlutterFlow Dependencies ### 3. iOS Configuration Go to **Custom Code** → **Configuration Files** and edit these files to add capabilities normally enabled in Xcode: **Properties → `Info.plist`:** ```xml theme={null} UIBackgroundModes remote-notification ``` FlutterFlow Info.plist **Entitlements → `Runner.entitlements`:** ```xml theme={null} aps-environment production ``` FlutterFlow Entitlements ### 4. Custom Actions Create custom actions in **Custom Code** → **Actions** for PNTA integration. Copy the required custom actions from our [FlutterFlow example project](https://marketplace.flutterflow.io/item/eD9VoY6IvHuucFq4iN9z) into your project. FlutterFlow Custom Actions ### 5. Wire Up Your App Add these custom actions to your app's **Initial Actions** in FlutterFlow. **Required:** **`pntaInitialize`**\ Initialize PNTA with your project ID and optional settings (defaults do not need to be declared): * `projectId` - your PNTA project ID (required) * `registerDevice` - set false if you want to use prompt registration in a specific flow in your app (default: true) * `autoHandleLinks` - true to automatically open URLs, requires pntaOnNotificationTap to be set up (default: false) * `showSystemUI` - true to show iOS notification banners and Android notification tray/sounds in the **foreground** (default: false) **Optional:** **`pntaOnNotificationTap`**\ Handle when users tap notifications from background or closed app. Required if using automatic link handling. **`pntaForegroundNotifications`**\ Listen for notifications when your app is active. Sends notification data to FlutterFlow app state for custom in-app messages. FlutterFlow Main Dart Initial Actions ### 6. Additional Methods These methods can be used anywhere in your app on specific pages: **`pntaRegisterDevice`**\ Use for delayed registration anywhere in the UI. **`pntaDeviceToken`**\ Device token getter if you want to store it. **`pntaUpdateMetadata`**\ Update device metadata in PNTA. **`pntaHandleLink`**\ Opens link passed in the notification payload. You can also use FlutterFlow's default "Launch URL" action which does pretty much the same. For routing within your app using notifications, use the URL scheme provided in **Settings** → **App Details** (e.g., `myapp://myapp.com/profile`). FlutterFlow Deep Linking Check out the example project for these additional custom actions and see how they're implemented in FlutterFlow's action builder. Test different initialize settings to find what works best for your app's user experience. ## Resources View package details and documentation on pub.dev Complete FlutterFlow project with PNTA integration # n8n Source: https://docs.pnta.io/integrations/n8n Set up push notifications in your n8n workflows using PNTA ## Prerequisites * n8n instance (self-hosted or cloud) * PNTA account with project ID (`prj_XXXXXXXXX`) * API key created in [PNTA Dashboard](https://app.pnta.io) * Platform keys configured in [PNTA Dashboard](https://app.pnta.io) (see [Platform Keys Setup](/resources/platform-keys)) ## Setup Steps ### 1. Install PNTA Node 1. Go to **Settings** → **Community nodes** 2. Click **Install** 3. Enter `@pnta/n8n-nodes-pnta` as the package name 4. Click **Install** to add the PNTA node to your n8n instance n8n Community Node Installation ### 2. Configure Authentication 1. Go back to your n8n dashboard 2. Click on **Create credential** in the top right corner 3. Search for **PNTA** and select it 4. Add the API key you created for your project in the PNTA Dashboard 5. Save the credential n8n PNTA Credentials Setup ### 3. Create Your First Workflow Now you're ready to create powerful workflows with PNTA! You can use PNTA nodes in various ways: **Webhook-Triggered Notifications:** * Create a workflow that starts with a **Webhook** node * Add a **PNTA** node to send push notifications when the webhook is triggered * Perfect for real-time notifications from external systems **Agent Workflows:** * Use PNTA nodes within AI agent workflows * Send notifications based on AI analysis or decision-making * Create intelligent notification systems that respond to data patterns n8n Agent Workflow **Scheduled Notifications:** * Combine **Cron** or **Schedule Trigger** nodes with PNTA nodes * Send regular updates, reminders, or status notifications * Automate recurring communication with your users **Conditional Notifications:** * Use **IF** nodes to create smart notification logic * Send different messages based on user data, time, or other conditions * Build sophisticated notification strategies **Need help with self-hosted n8n?** If you need assistance setting up a self-hosted n8n instance, we're here to help! Just reach out to [support@pnta.io](mailto:support@pnta.io) and we'll get you sorted with your own n8n deployment. ## Resources Official PNTA node for n8n workflows Learn more about PNTA integration with n8n # Supabase Source: https://docs.pnta.io/integrations/supabase Trigger push notifications directly from your Supabase database using PNTA ## Prerequisites * Supabase project * PNTA account with project ID (`prj_XXXXXXXXX`) * Platform keys configured in [PNTA Dashboard](https://app.pnta.io) (see [Platform Keys Setup](/resources/platform-keys)) * Devices registered via a PNTA client SDK, with relevant identifiers stored in device metadata (e.g. `user_id`) ## Setup Steps ### 1. Connect Your Supabase Project 1. In the [PNTA Dashboard](https://app.pnta.io) sidebar, open the **Integrations** section and click **Supabase** 2. Click **Connect** 3. Authorize PNTA via OAuth 4. Link a Supabase project to your PNTA project 5. Go to **Rules** PNTA uses OAuth to connect to your Supabase project. No manual database configuration or SQL is required. Everything is set up automatically. Linking a Supabase project to PNTA ### 2. Create a Notification Rule From **Rules**, click **New Rule**. Supabase rule overview in the PNTA Dashboard We'll walk through an order confirmation push using this `orders` table as the example: ```sql theme={null} create table orders ( id uuid primary key default gen_random_uuid(), order_number text not null unique, customer_id text not null, customer_name text not null, customer_email text not null, total numeric(10, 2) not null, currency text not null default 'USD', status text not null default 'pending', carrier text, shipped_at timestamptz, created_at timestamptz not null default now() ); ``` Give the rule a description so you can identify it later: * **Description**: `Notify the customer when they place a paid order` Then set the trigger, which is the table and event that fire the rule: * **Table**: `orders` * **Event**: `insert` ### 3. Add Conditions Conditions decide **who** receives the push and **when** it fires. Each rule typically combines: * A **device filter** (`metadata.*` or `identifiers.*`) that routes to the right devices * A **row filter** (`row.*`) that gates the rule on row values When a row changes, PNTA matches a column from that row against a field in each registered device's metadata. Only matching devices receive the push, so your client SDK must register devices with the matching field (in this case, `user_id` set to the customer's ID). For the order confirmation rule: * `metadata.user_id` `is_equal` `{{customer_id}}` targets only the customer's devices * `row.status` `is_equal` `paid` ensures the rule only fires once the order is paid Rule builder showing trigger and conditions ### 4. Configure the Template Use `{{column_name}}` placeholders to pull values from the row directly into the notification: * **Title**: `Order #{{order_number}} confirmed 🎉` * **Body**: `Thanks {{customer_name}}! We're preparing your ${{total}} order.` * **Link**: `myapp://orders/{{order_number}}` Any column in the row is available as a placeholder. The preview panel on the right lets you enter an existing row ID and see exactly what the notification will look like with real values filled in, so you can sanity-check your template before saving. Rule builder showing the template section Save the rule and it's live. ### 5. Test It Paste this into the Supabase SQL editor to trigger the rule: ```sql theme={null} insert into orders (order_number, customer_id, customer_name, customer_email, total, status) values ('1001', 'user_123', 'Alex', 'alex@example.com', 49.00, 'paid'); ``` Then open the **Notifications** dashboard in PNTA. Every notification PNTA sends shows up there, so you'll find the new one at the top along with the devices it was sent to. Any device registered with `user_id = "user_123"` in its metadata receives the push. ## Use Cases Orders is just one example. The same primitives (`insert`/`update`/`delete` triggers, row placeholders, metadata routing, and row conditions) work against any table you have. Chat messages, comments, friend requests, booking confirmations, low-stock alerts, content moderation flags, and anything else you store in Supabase can drive a push. Two more rules built against the same `orders` table to show the range: **Order shipped** fires on `update` when the status flips to `shipped`: * **Trigger**: `orders` / `update` * **Title**: `Your order is on its way! 📦` * **Body**: `Order #{{order_number}} shipped via {{carrier}}` * **Conditions**: `metadata.user_id` `is_equal` `{{customer_id}}` + `row.status` `is_equal` `shipped` **High value order** fires on `insert` when the total exceeds \$200: * **Trigger**: `orders` / `insert` * **Title**: `Thank you for your order, {{customer_name}}!` * **Body**: `Your ${{total}} order #{{order_number}} is being prepared with care` * **Conditions**: `metadata.user_id` `is_equal` `{{customer_id}}` + `row.total` `greater_than` `200` ### Realtime chat Chat is just another table. Say you store messages like this: ```sql theme={null} create table messages ( id uuid primary key default gen_random_uuid(), conversation_id uuid not null, sender_id text not null, sender_name text not null, recipient_id text not null, body text not null, created_at timestamptz not null default now() ); ``` Add an `insert` rule that notifies the recipient whenever a new message lands: * **Trigger**: `messages` / `insert` * **Title**: `{{sender_name}}` * **Body**: `{{body}}` * **Link**: `myapp://conversations/{{conversation_id}}` * **Conditions**: `metadata.user_id` `is_equal` `{{recipient_id}}` PNTA fires on the insert via Supabase Database Webhooks, independent of Supabase Realtime. It works whether or not Realtime is enabled, and the two run side by side. ## Troubleshooting **No notification fires.** Confirm that at least one device is registered with the matching field in its metadata (for this example, `user_id` set to the row's `customer_id`). Without a metadata match, PNTA has no devices to deliver to. **Rule won't save.** Every rule must include at least one device filter, either a `metadata.*` or an `identifiers.*` condition. PNTA uses it to match the incoming row to specific devices, so without it there's no way to determine who should receive the push and the rule can't be saved. ## Resources Learn more about Supabase # MCP Server Source: https://docs.pnta.io/mcp-server Connect PNTA documentation to AI assistants using Model Context Protocol ## Setup ### Prerequisites * Node.js installed * PNTA API key from your [Dashboard](https://app.pnta.io) ### Installation **Step 1:** Add the PNTA MCP server ```bash theme={null} npx mint-mcp add pnta ``` **Step 2:** Enter your PNTA API key when prompted **Step 3:** Run the server using the command displayed ```bash theme={null} node path/to/generated/server.js ``` ## Supported Clients Works with **[Claude Desktop](https://claude.ai/download)**, **[Cursor](https://www.cursor.com/)**, and **[Windsurf](https://windsurf.com/)**. ## Usage Ask your AI assistant questions about PNTA: * "How do I set up PNTA with Flutter?" * "What are the notification API endpoints?" * "How do autoHandleLinks work?" * "Show me Android platform setup requirements" * etc. ## Troubleshooting * **Server won't start**: Check Node.js version and API key validity * **AI can't connect**: Ensure server is running and ports are open ## Support * [Troubleshooting guides](/guides/flutter/troubleshooting) * [support@pnta.io](mailto:support@pnta.io) * [Discord community](https://discord.gg/RQ7AuS8EC9) # Platform Keys Setup Source: https://docs.pnta.io/resources/platform-keys Configure Google Service Account and Apple P8 keys for push notifications ## Google Service Account JSON (Android) To send push notifications to Android devices, you need a Google Service Account key from Firebase. ### 1. Create Firebase Project 1. Go to the [Firebase Console](https://console.firebase.google.com/) 2. Create a new project or select an existing one 3. Register your Android app using your package name (e.g., `com.example.your_app`) ### 2. Generate Service Account Key 1. In the Firebase Console, go to **Project Settings** → **Service accounts** 2. Click **Generate new private key** 3. Download the JSON file - this is your service account key ### 3. Configure in PNTA Dashboard 1. Go to your [PNTA dashboard](https://app.pnta.io) 2. Navigate to **Project Setup** 3. Go to the **FCM Configuration** tab 4. Upload your Google Service Account JSON file 5. Your Android push notifications are now configured ## Apple P8 Key (iOS) To send push notifications to iOS devices, you need an Apple Push Notification service (APNs) key. ### 1. Create APNs Key 1. Go to the [Apple Developer Console](https://developer.apple.com/account/resources/authkeys/list) 2. Click the **+** button to create a new key 3. Enter a key name (e.g., "PNTA Push Notifications") 4. Check **Apple Push Notifications service (APNs)** 5. Select **Production** for the key environment 6. Click **Continue** and then **Register** ### 2. Download Key 1. Download the `.p8` file - this is your APNs key 2. Note the **Key ID** (displayed on the download page) 3. Note your **Team ID** (found in your Apple Developer account settings) ### 3. Configure in PNTA Dashboard 1. Go to your [PNTA dashboard](https://app.pnta.io) 2. Navigate to **Project Setup** 3. Go to the **APN Configuration** tab 4. Upload your `.p8` file 5. Enter your **Key ID** and **Team ID** 6. Enter your **App Bundle ID** (e.g., `com.example.your_app`) 7. Your iOS push notifications are now configured