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

# Quickstart

> Build your first LaunchMyStore app in 5 minutes

<Note>
  **Prefer the CLI?** Install `@launchmystore/cli` and skip steps 1–4: `lms auth login` then `lms app create` scaffolds a working app, registers it with your developer account, writes credentials, and starts a Cloudflare tunnel via `lms app dev`. See [CLI Setup](/getting-started/cli-setup) for the fast path.
</Note>

## Prerequisites

<CardGroup cols={2}>
  <Card title="Node.js 18+" icon="node-js" href="https://nodejs.org">
    Required for development
  </Card>

  <Card title="Developer Account" icon="user" href="https://app.launchmystore.io/developer">
    Sign up for free
  </Card>
</CardGroup>

## Step 1: Create a Developer Account

1. Go to [app.launchmystore.io/developer](https://app.launchmystore.io/developer)
2. Sign up or log in with your LaunchMyStore account
3. Navigate to **Apps** in the developer dashboard

## Step 2: Create Your App

<Steps>
  <Step title="Click Create App">
    In the developer dashboard, click the **Create App** button.
  </Step>

  <Step title="Configure App Details">
    Fill in your app information:

    * **App name**: A descriptive name for your app
    * **App handle**: URL-safe identifier (e.g., `my-awesome-app`)
    * **App URL**: Where your app is hosted (e.g., `https://my-app.com`)
    * **Redirect URLs**: OAuth callback URLs
  </Step>

  <Step title="Select Scopes">
    Choose the permissions your app needs:

    ```
    read_products, write_products
    read_orders, write_orders
    read_customers
    ```
  </Step>

  <Step title="Save Credentials">
    After creation, you'll receive:

    * **Client ID**: Public identifier for your app
    * **Client Secret**: Keep this secure, never expose publicly
  </Step>
</Steps>

## Step 3: Set Up Your Project

Create a new project with your preferred framework:

<CodeGroup>
  ```bash Node.js theme={null}
  mkdir my-lms-app && cd my-lms-app
  npm init -y
  npm install express @launchmystore/app-bridge
  ```

  ```bash React theme={null}
  npx create-react-app my-lms-app
  cd my-lms-app
  npm install @launchmystore/app-bridge @launchmystore/app-bridge-react
  ```
</CodeGroup>

## Step 4: Implement the `/auth` install handoff

Your app receives its first access token through the managed
[install handoff](/getting-started/install-handoff): when a merchant
installs your app, LaunchMyStore redirects their browser to
`{appUrl}/auth?shop=…&storeId=…&code=…&state=…&host=…&timestamp=…&hmac=…`.
Verify the HMAC, exchange the `code`, and land the merchant back in
their admin. (Do **not** redirect merchants to
`/apps/oauth/authorize` — it is a merchant-authenticated JSON API used
by the LaunchMyStore admin, not a browser flow.)

```javascript server.js theme={null}
const express = require('express');
const crypto = require('crypto');
const app = express();

const CLIENT_ID = process.env.LMS_CLIENT_ID;
const CLIENT_SECRET = process.env.LMS_CLIENT_SECRET;

// Install handoff — LaunchMyStore redirects the merchant here on install
app.get('/auth', async (req, res) => {
  const params = req.query;

  // 1. Verify the HMAC (raw query string minus the hmac= field)
  const qs = req.url.split('?')[1]
    .split('&')
    .filter((p) => !p.startsWith('hmac='))
    .join('&');
  const expected = crypto
    .createHmac('sha256', CLIENT_SECRET)
    .update(qs)
    .digest('hex');
  const a = Buffer.from(String(params.hmac));
  const b = Buffer.from(expected);
  if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
    return res.status(401).send('Invalid HMAC');
  }

  // 2. Exchange the pre-authorized code for tokens
  const response = await fetch('https://api.launchmystore.io/apps/oauth/token', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      client_id: CLIENT_ID,
      client_secret: CLIENT_SECRET,
      code: params.code,
      grant_type: 'authorization_code',
      state: params.state          // echo the handoff state verbatim
    })
  });

  // Token payload is wrapped in the platform envelope — read `data`
  const { data } = await response.json();

  // 3. Store tokens keyed by the immutable storeId (not the shop host)
  await saveTokens(params.storeId, data.access_token, data.refresh_token);

  // 4. Land the merchant back in their admin
  res.redirect(Buffer.from(params.host, 'base64').toString('utf8'));
});

app.listen(3000);
```

## Step 5: Make API Calls

Use your access token to call the API:

```javascript theme={null}
const accessToken = await getAccessToken(storeId);

const response = await fetch('https://api.launchmystore.io/api/v1/products.json', {
  headers: {
    'Authorization': `Bearer ${accessToken}`,
    'Content-Type': 'application/json'
  }
});

const products = await response.json();
```

## Step 6: Add App Bridge (Embedded Apps)

If your app is embedded in the LaunchMyStore admin:

```javascript theme={null}
import { createApp } from '@launchmystore/app-bridge';

const app = createApp({
  apiKey: 'your-client-id',
  host: new URLSearchParams(location.search).get('host')
});

// Show a toast notification — dispatch(actionName, payload)
app.dispatch('TOAST_SHOW', { message: 'Hello from my app!', duration: 3000 });
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Build Extensions" icon="puzzle-piece" href="/extensions/overview">
    Add UI to storefronts, checkout, and admin
  </Card>

  <Card title="Create Functions" icon="code" href="/functions/overview">
    Custom logic for shipping, payments, and more
  </Card>

  <Card title="App Bridge" icon="bridge" href="/app-bridge/overview">
    Communicate with the host application
  </Card>

  <Card title="API Reference" icon="book" href="/api-reference/overview">
    Full REST API documentation
  </Card>
</CardGroup>
