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

# Quickstart

> Start building with the Twigz API in under 5 minutes

## Setup your development environment

Learn how to update your docs locally and deploy them to the public.

### Install Convex Client

<CodeGroup>
  ```bash npm theme={null}
  npm install convex
  ```

  ```bash yarn theme={null}
  yarn add convex
  ```

  ```bash pnpm theme={null}
  pnpm add convex
  ```
</CodeGroup>

### Configure Environment

Create a `.env.local` file in your project root:

```bash theme={null}
NEXT_PUBLIC_CONVEX_URL=https://your-deployment.convex.cloud
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY=pk_test_...
CLERK_SECRET_KEY=sk_test_...
```

<Warning>
  Never commit your secret keys to version control. Use environment variables for all sensitive configuration.
</Warning>

### Initialize Convex Client

<CodeGroup>
  ```typescript React theme={null}
  // convex/client.ts
  import { ConvexReactClient } from "convex/react";

  const convex = new ConvexReactClient(
    process.env.NEXT_PUBLIC_CONVEX_URL!
  );

  export default convex;
  ```

  ```typescript Node.js theme={null}
  // server/convex.ts
  import { ConvexHttpClient } from "convex/node";

  const convex = new ConvexHttpClient(
    process.env.CONVEX_URL!
  );

  export default convex;
  ```

  ```javascript Vanilla JS theme={null}
  // client/convex.js
  import { ConvexHttpClient } from "convex/browser";

  const convex = new ConvexHttpClient(
    process.env.CONVEX_URL
  );

  export default convex;
  ```
</CodeGroup>

## Make your first request

Let's start by fetching all available categories:

<CodeGroup>
  ```typescript TypeScript theme={null}
  import { api } from "./convex/_generated/api";
  import convex from "./convex/client";

  async function getCategories() {
    try {
      const categories = await convex.query(
        api.shared.categories.getParents
      );
      
      console.log("Available categories:", categories);
      return categories;
    } catch (error) {
      console.error("Error fetching categories:", error);
    }
  }

  // Call the function
  getCategories();
  ```

  ```javascript JavaScript theme={null}
  async function getCategories() {
    try {
      const categories = await convex.query(
        "shared.categories.getParents"
      );
      
      console.log("Available categories:", categories);
      return categories;
    } catch (error) {
      console.error("Error fetching categories:", error);
    }
  }
  ```

  ```python Python theme={null}
  import requests
  import os

  def get_categories():
      url = f"{os.getenv('CONVEX_URL')}/api/query"
      
      payload = {
          "path": "shared.categories.getParents",
          "args": {}
      }
      
      headers = {
          "Content-Type": "application/json",
          "Authorization": f"Bearer {os.getenv('CONVEX_TOKEN')}"
      }
      
      response = requests.post(url, json=payload, headers=headers)
      
      if response.status_code == 200:
          return response.json()
      else:
          print(f"Error: {response.status_code}")
          return None

  categories = get_categories()
  print(categories)
  ```
</CodeGroup>

Expected response:

```json theme={null}
[
  {
    "_id": "k123456789",
    "name": "Food & Restaurants",
    "parent": null,
    "isActive": true,
    "_creationTime": 1640995200000
  },
  {
    "_id": "k987654321", 
    "name": "Electronics",
    "parent": null,
    "isActive": true,
    "_creationTime": 1640995200000
  }
]
```

## Authentication

Most API endpoints require authentication. Here's how to set it up:

<Steps>
  <Step title="Install Clerk">
    ```bash theme={null}
    npm install @clerk/nextjs
    ```
  </Step>

  <Step title="Configure Clerk Provider">
    ```tsx theme={null}
    // app/layout.tsx
    import { ClerkProvider } from '@clerk/nextjs'
    import { ConvexProviderWithClerk } from "convex/react-clerk";
    import convex from "./convex/client";

    export default function RootLayout({
      children,
    }: {
      children: React.ReactNode
    }) {
      return (
        <ClerkProvider>
          <ConvexProviderWithClerk client={convex}>
            <html lang="en">
              <body>{children}</body>
            </html>
          </ConvexProviderWithClerk>
        </ClerkProvider>
      )
    }
    ```
  </Step>

  <Step title="Use Authenticated Queries">
    ```typescript theme={null}
    import { useQuery } from "convex/react";
    import { api } from "./convex/_generated/api";

    function MyComponent() {
      const store = useQuery(
        api.stores.queries.getStoreByAuthenticatedOwner
      );
      
      if (store === undefined) return <div>Loading...</div>;
      if (store === null) return <div>No store found</div>;
      
      return <div>Store: {store.name}</div>;
    }
    ```
  </Step>
</Steps>

## Common Use Cases

### 1. Register a Customer

```typescript theme={null}
import { api } from "./convex/_generated/api";

const customerId = await convex.mutation(
  api.customers.account.registerCustomer,
  {
    preferredLanguage: "en"
  }
);

console.log("Customer registered:", customerId);
```

### 2. Create a Store

```typescript theme={null}
const storeId = await convex.mutation(
  api.stores.operations.registerStore,
  {
    name: "Mario's Pizza",
    primaryCategory: "k123456789", // Food category
    logoId: "s123456789", // Upload logo first
    tradeLicenseId: "s987654321" // Upload license first
  }
);
```

### 3. Add Products to Cart

```typescript theme={null}
await convex.mutation(api.customers.cart.addToCart, {
  customerId: "c123456789",
  storeId: "j123456789", 
  productId: "p123456789",
  quantity: 2
});
```

### 4. Create an Order

```typescript theme={null}
const order = await convex.mutation(
  api.customers.cartToOrder.createOrderFromCart,
  {
    customerId: "c123456789",
    storeId: "j123456789",
    deliveryAddress: {
      fullAddress: "123 Main St, Apt 4B",
      city: "ct123456789",
      area: "ar123456789",
      phoneNumber: "+971501234567"
    },
    deliveryType: "delivery",
    deliveryFee: 5.00,
    paymentMethod: "card",
    paymentIntentId: "pi_123456789"
  }
);
```

## Error Handling

Always implement proper error handling:

```typescript theme={null}
import { ConvexError } from "convex/values";

try {
  const result = await convex.mutation(
    api.shared.products.createProduct,
    {
      name: "New Product",
      // ... other fields
    }
  );
} catch (error) {
  if (error instanceof ConvexError) {
    // Handle Convex-specific errors
    console.error("Convex error:", error.data);
  } else {
    // Handle other errors
    console.error("Unexpected error:", error);
  }
}
```

## Rate Limiting

The API implements rate limiting to ensure fair usage:

* **Queries**: 1000 requests per minute
* **Mutations**: 100 requests per minute
* **Actions**: 50 requests per minute

<Tip>
  Use the `useQuery` hook for real-time data that updates automatically, and `useMutation` for user actions.
</Tip>

## Next Steps

<CardGroup cols={2}>
  <Card title="Explore API Reference" icon="code" href="/api-reference/shared/products">
    Dive deep into all available endpoints
  </Card>

  <Card title="Authentication Guide" icon="shield-check" href="/essentials/authentication">
    Learn about user authentication and permissions
  </Card>

  <Card title="Payment Integration" icon="credit-card" href="/api-reference/customers/payments">
    Set up Stripe payments and marketplace fees
  </Card>

  <Card title="Real-time Features" icon="bolt" href="/essentials/real-time">
    Build reactive UIs with live data
  </Card>
</CardGroup>

## Need Help?

<AccordionGroup>
  <Accordion title="How do I handle file uploads?">
    Use the `generateUploadUrl` function to get a secure upload URL:

    ```typescript theme={null}
    const uploadUrl = await convex.mutation(
      api.shared.utils.generateUploadUrl
    );

    // Upload file to the URL
    const response = await fetch(uploadUrl, {
      method: "POST",
      body: file
    });

    const { storageId } = await response.json();
    ```
  </Accordion>

  <Accordion title="How do I implement real-time updates?">
    Use the `useQuery` hook which automatically updates when data changes:

    ```typescript theme={null}
    const orders = useQuery(api.stores.queries.getStoreOrders, {
      storeId: "j123456789",
      status: "pending"
    });

    // Component re-renders automatically when orders change
    ```
  </Accordion>

  <Accordion title="How do I handle pagination?">
    Use the pagination options in queries:

    ```typescript theme={null}
    const stores = await convex.query(
      api.customers.explore.getStoresWithPagination,
      {
        paginationOpts: { 
          numItems: 20, 
          cursor: null // or previous cursor
        }
      }
    );
    ```
  </Accordion>
</AccordionGroup>
