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

# Quickstart

> Sign in, then run the cross-device-aware wallet flow — in your platform.

Two steps everywhere: **sign in**, then run the **wallet flow**. Pick your platform
in each code group.

<Steps>
  <Step title="Install">
    <CodeGroup>
      ```bash React Native theme={null}
      npm i @meru.app/device-signer
      ```

      ```yaml Flutter theme={null}
      # pubspec.yaml
      dependencies:
        meru_device_wallet: ^0.1.0
      ```

      ```swift iOS theme={null}
      // Package.swift
      .package(url: "https://github.com/getmeru/meru-device-wallet-swift.git", from: "0.1.0")
      ```

      ```kotlin Android theme={null}
      // build.gradle.kts
      implementation("app.meru:meru-device-wallet:0.1.0")
      ```
    </CodeGroup>
  </Step>

  <Step title="Sign in (email OTP or passkey)">
    <CodeGroup>
      ```ts React Native theme={null}
      import { createMeruAuth } from "@meru.app/device-signer/auth";
      import * as SecureStore from "expo-secure-store";

      const auth = createMeruAuth({
        authBase: "https://stablecoin-api.getmeru.com",
        companyId: "<your public company id>",
        passkeyDomain: "yourapp.com",
        storage: {
          getItem: (k) => SecureStore.getItemAsync(k),
          setItem: (k, v) => SecureStore.setItemAsync(k, v),
          removeItem: (k) => SecureStore.deleteItemAsync(k),
        },
      });

      await auth.sendEmailCode(email);
      const session = await auth.verifyEmailCode(email, code);
      // returning users: const session = await auth.loginWithPasskey();
      ```

      ```dart Flutter theme={null}
      final auth = MeruAuth(
        authBase: 'https://stablecoin-api.getmeru.com',
        companyId: '<your public company id>',
        passkeyDomain: 'yourapp.com',
      );

      await auth.sendEmailCode(email);
      final session = await auth.verifyEmailCode(email, code);
      // returning users: final session = await auth.loginWithPasskey();
      ```

      ```swift iOS theme={null}
      let auth = MeruAuth(
          authBase: URL(string: "https://stablecoin-api.getmeru.com")!,
          companyId: "<your public company id>",
          passkeyDomain: "yourapp.com"
      )

      _ = try await auth.sendEmailCode(email)
      let session = try await auth.verifyEmailCode(email, code: code)
      // returning users: let session = try await auth.loginWithPasskey()
      ```

      ```kotlin Android theme={null}
      val auth = MeruAuth(
          context = applicationContext,
          authBase = "https://stablecoin-api.getmeru.com",
          companyId = "<your public company id>",
          passkeyDomain = "yourapp.com",
      )

      auth.sendEmailCode(email)
      val session = auth.verifyEmailCode(email, code)
      // returning users: val session = auth.loginWithPasskey(activity)
      ```
    </CodeGroup>
  </Step>

  <Step title="Run the wallet flow">
    `status()` tells each device exactly what to do — so a second phone gets
    **recover**, never a duplicate wallet.

    <CodeGroup>
      ```ts React Native theme={null}
      import { MeruDeviceWallet } from "@meru.app/device-signer/wallet";

      const wallet = new MeruDeviceWallet({
        baseUrl: "https://your-app.com/api/meru",
        userId: session.user.id,
        getToken: async () => auth.current()?.token ?? null,
      });

      const { state } = await wallet.status();
      if (state === "create") await wallet.enroll({ activate: true });
      else if (state === "recover") await wallet.recover();

      await wallet.send("GB7C…FB2Q", 5); // device-signed, Meru pays the fee
      ```

      ```dart Flutter theme={null}
      final wallet = MeruDeviceWallet(
        baseUrl: 'https://your-app.com/api/meru',
        getToken: () async => auth.current?.token,
        keyId: 'meru.device-key.${session.user.id}',
      );

      switch ((await wallet.status()).state) {
        case WalletState.create:  await wallet.enroll(activate: true);
        case WalletState.recover: await wallet.recover();
        case WalletState.ready:   break;
      }
      await wallet.send('GB7C…FB2Q', 5);
      ```

      ```swift iOS theme={null}
      let wallet = MeruDeviceWallet(
          baseURL: URL(string: "https://your-app.com/api/meru")!,
          userId: session.user.id,
          getToken: { auth.current?.token }
      )

      switch try await wallet.status().state {
      case .create:  try await wallet.enroll(activate: true)
      case .recover: try await wallet.recover()
      case .ready:   break
      }
      let txHash = try await wallet.send(to: "GB7C…FB2Q", amount: 5)
      ```

      ```kotlin Android theme={null}
      val wallet = MeruDeviceWallet(
          baseUrl = "https://your-app.com/api/meru",
          keys = DeviceKeyStore(applicationContext),
          userId = session.user.id,
          getToken = { auth.current?.token },
      )

      when (wallet.status().state) {
          WalletState.CREATE  -> wallet.enroll(activate = true)
          WalletState.RECOVER -> wallet.recover()
          WalletState.READY   -> {}
      }
      val txHash = wallet.send("GB7C…FB2Q", 5.0)
      ```
    </CodeGroup>
  </Step>
</Steps>

<Note>
  The `authBase` + `companyId` come from Meru; the `backendBase`
  (`https://your-app.com/api/meru`) is your own server running `createMeruHandler`.
  See [Overview](/self-custody/overview#the-two-endpoints).
</Note>
