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

# Quickstart

> From API key to a working support ticket in about five minutes.

This is the shortest path on any platform: install, initialize, identify,
and open a ticket. Pick your framework below. The steps map 1:1.

<Steps>
  <Step title="Get your publishable API key">
    In the [ClarioDesk dashboard](https://dashboard.clariodesk.com), create an app and
    copy its publishable key, which starts with `pk_live_`. This key only
    authorizes a fresh install to register a device; it can't read tickets or
    impersonate users, so it's safe to ship in your app binary.
  </Step>

  <Step title="Install the SDK">
    <CodeGroup>
      ```bash Flutter theme={null}
      flutter pub add clariodesk
      ```

      ```bash React Native theme={null}
      npm install @clariodesk/react-native react-native-get-random-values
      # then pick secure storage for your stack:
      npx expo install expo-secure-store   # Expo
      npm install react-native-keychain    # bare RN
      ```

      ```swift Swift theme={null}
      // Xcode: File → Add Package Dependencies…, or in Package.swift:
      .package(url: "https://github.com/clariodesk/clariodesk-swift", from: "0.1.1")
      // Products: ClarioDesk (headless) and/or ClarioDeskUI (prebuilt screens)
      ```
    </CodeGroup>
  </Step>

  <Step title="Initialize once at app start">
    The first call generates the hardware device key and registers it. Later
    launches reuse it with no network round-trip.

    <CodeGroup>
      ```dart Flutter theme={null}
      import 'package:clariodesk/clariodesk.dart';

      Future<void> main() async {
        WidgetsFlutterBinding.ensureInitialized();
        await ClarioDesk.init(apiKey: 'pk_live_…');
        runApp(const MyApp());
      }
      ```

      ```ts React Native theme={null}
      // index.js: the very first import, before anything else
      import 'react-native-get-random-values';
      import { ClarioDesk } from '@clariodesk/react-native';

      await ClarioDesk.init({ apiKey: 'pk_live_…' });
      ```

      ```swift Swift theme={null}
      import ClarioDesk

      // App.init or AppDelegate — fire-and-forget, no await:
      ClarioDesk.initialize(.init(apiKey: "pk_live_…"))
      ```
    </CodeGroup>
  </Step>

  <Step title="Identify the user">
    Call `identify()` once your own auth knows who the user is. It's metadata
    only: the device key is the real identity, so this grants no access. It's
    idempotent, so call it on every launch for logged-in users.

    <CodeGroup>
      ```dart Flutter theme={null}
      await ClarioDesk.identify(
        externalId: user.id,
        email: user.email,
        traits: {'plan': 'pro'},
      );
      ```

      ```ts React Native theme={null}
      await ClarioDesk.identify({ externalId: user.id, email: user.email });
      ```

      ```swift Swift theme={null}
      try await ClarioDesk.identify(
        externalId: user.id,
        email: user.email,
        traits: ["plan": "pro"]
      )
      ```
    </CodeGroup>

    <Note>
      **Already have signed-in users?** When you add ClarioDesk to an app that is
      already in use, identify those users on launch from your saved session, not
      only on your login screen. Existing users rarely pass through login again,
      so a login-only call leaves them unidentified. Full walkthrough:
      [Flutter](/integrate-flutter), [React Native](/integrate-react-native), or
      [Swift](/integrate-swift).
    </Note>
  </Step>

  <Step title="Open a ticket and stream replies">
    <CodeGroup>
      ```dart Flutter theme={null}
      final t = await ClarioDesk.createTicket(
        subject: 'Upload broken',
        body: 'Tapping upload does nothing.',
      );

      // Reactive thread: primes, then live updates.
      StreamBuilder<List<Message>>(
        stream: ClarioDesk.messagesStream(t.id),
        builder: (_, snap) => /* render messages */,
      );
      ```

      ```ts React Native theme={null}
      const { ticket } = await ClarioDesk.createTicket({
        subject: '',
        body: 'Tapping upload does nothing.',
      });

      // Reactive thread: subscribe returns an unsubscribe fn.
      const off = ClarioDesk.subscribeMessages(ticket.id, (messages) =>
        render(messages),
      );
      ```

      ```swift Swift theme={null}
      let (ticket, _) = try await ClarioDesk.createTicket(
        subject: "Upload broken",
        body: "Tapping upload does nothing."
      )

      // Reactive thread: replay-last AsyncStream, primes then live-updates.
      for try await messages in ClarioDesk.messages(ticketId: ticket.id) {
        render(messages)
      }
      ```
    </CodeGroup>
  </Step>
</Steps>

That's a complete loop: a real ticket lands in your dashboard inbox, and the
agent's reply streams back to the device live.

<Card title="Prefer not to build the UI?" icon="layout-panel-left" href="/flutter/prebuilt-ui">
  Use the prebuilt chat instead: one call opens a themeable inbox. See the
  prebuilt UI guide for [Flutter](/flutter/prebuilt-ui),
  [React Native](/react-native/prebuilt-ui), or [Swift](/swift/prebuilt-ui).
</Card>
