# Internal API Keys - Documentation

## Overview

Internal API keys provide system-level access to all webshop data without being tied to a specific user account. These keys are designed for:

- Internal system integrations
- Backend services
- Analytics platforms
- Administrative tools
- Automated processes

**Key Differences from User API Keys:**
- **Internal keys** (`int_shopcall_xxx`) - Access ALL webshops across all users
- **User keys** (`api_shopcall_xxx`) - Access only the user's own webshops

## Features

- ✅ Non-user-based authentication
- ✅ Access to all connected webshops (Shopify, WooCommerce, ShopRenter)
- ✅ Unified REST API endpoint (`shop-data-api`)
- ✅ Rate limiting (200 requests/minute)
- ✅ Not visible in UI (internal use only)
- ✅ Secure bcrypt hashing
- ✅ Optional expiration dates
- ✅ Usage tracking (last_used_at)
- ✅ Supports products, orders, and customers data

## Database Schema

### `internal_api_keys` Table

```sql
CREATE TABLE internal_api_keys (
  id UUID PRIMARY KEY,
  key_name TEXT NOT NULL,
  api_key TEXT NOT NULL UNIQUE,
  key_hash TEXT NOT NULL,
  description TEXT,
  permissions JSONB DEFAULT '{"all_webshops": true, "read_products": true, "read_orders": true, "read_customers": true}',
  is_active BOOLEAN DEFAULT true,
  last_used_at TIMESTAMPTZ,
  expires_at TIMESTAMPTZ,
  created_at TIMESTAMPTZ DEFAULT NOW(),
  updated_at TIMESTAMPTZ DEFAULT NOW(),
  created_by TEXT
);
```

**Key Format:** `int_shopcall_[48-character-random-string]`

**Permissions:** Stored as JSONB with flexible permission model

## Creating an Internal API Key

Internal API keys must be created **manually via SQL** (not exposed in UI):

### Step 1: Generate the API Key

Use the provided helper script or generate manually:

```javascript
// Generate key in Deno/Node.js
const characters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-";
const length = 48;
let apiKey = "int_shopcall_";
for (let i = 0; i < length; i++) {
  apiKey += characters.charAt(Math.floor(Math.random() * characters.length));
}
console.log(apiKey);
```

### Step 2: Hash the API Key

Hash the API key using bcrypt (cost factor 12):

```bash
# Using bcrypt CLI (if available)
bcrypt hash "int_shopcall_YOUR_KEY_HERE" 12

# Or use online bcrypt tool (cost: 12)
# https://bcrypt-generator.com/
```

### Step 3: Insert into Database

```sql
INSERT INTO internal_api_keys (
  key_name,
  api_key,
  key_hash,
  description,
  created_by,
  expires_at
) VALUES (
  'Analytics Service',
  'int_shopcall_YOUR_GENERATED_KEY',
  '$2b$12$YOUR_BCRYPT_HASH_HERE',
  'Internal API key for analytics platform',
  'admin',
  NULL  -- or '2025-12-31 23:59:59+00' for expiration
);
```

**IMPORTANT:** Store the plain `int_shopcall_xxx` key securely! It cannot be retrieved later.

## API Endpoints

All endpoints are available at: `https://YOUR_PROJECT.supabase.co/functions/v1/shop-data-api`

### Authentication

Include the internal API key in the Authorization header:

```bash
Authorization: Bearer int_shopcall_YOUR_KEY_HERE
```

### Available Endpoints

#### 1. List All Stores
```bash
GET /shop-data-api/stores
```

**Response:**
```json
{
  "success": true,
  "data": [
    {
      "id": "uuid",
      "store_name": "My Shop",
      "store_url": "https://myshop.com",
      "platform_name": "shopify",
      "is_active": true,
      "connected_at": "2025-01-15T10:00:00Z",
      "sync_status": "completed",
      "user_id": "uuid"
    }
  ],
  "count": 1,
  "auth_type": "internal",
  "fetched_at": "2025-01-31T17:00:00Z"
}
```

#### 2. List Products
```bash
GET /shop-data-api/products?store_id={uuid}&page=1&limit=25
```

**Query Parameters:**
- `store_id` (required) - UUID of the store
- `page` (optional) - Page number (default: 1)
- `limit` (optional) - Items per page (default: 25, max: 100)

**Response:**
```json
{
  "success": true,
  "platform": "shopify",
  "data": [
    {
      "id": "12345",
      "name": "Product Name",
      "sku": "SKU-001",
      "price": 29.99,
      "stock_quantity": 100,
      ...
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 25,
    "has_more": true
  },
  "fetched_at": "2025-01-31T17:00:00Z"
}
```

#### 3. List Orders
```bash
GET /shop-data-api/orders?store_id={uuid}&status=completed&page=1&limit=25
```

**Query Parameters:**
- `store_id` (required)
- `status` (optional) - Filter by order status
- `page`, `limit` (optional)

#### 4. List Customers
```bash
GET /shop-data-api/customers?store_id={uuid}&page=1&limit=25
```

**Query Parameters:**
- `store_id` (required)
- `page`, `limit` (optional)

#### 5. Get Single Resource by ID
```bash
GET /shop-data-api/products/{id}?store_id={uuid}
GET /shop-data-api/orders/{id}?store_id={uuid}
GET /shop-data-api/customers/{id}?store_id={uuid}
```

## Usage Examples

### cURL Example

```bash
# List all stores
curl -X GET \
  'https://ztklqodcdjeqpsvhlpud.supabase.co/functions/v1/shop-data-api/stores' \
  -H 'Authorization: Bearer int_shopcall_YOUR_KEY_HERE'

# Get products from a specific store
curl -X GET \
  'https://ztklqodcdjeqpsvhlpud.supabase.co/functions/v1/shop-data-api/products?store_id=YOUR_STORE_UUID&limit=10' \
  -H 'Authorization: Bearer int_shopcall_YOUR_KEY_HERE'
```

### JavaScript Example

```javascript
const API_URL = 'https://ztklqodcdjeqpsvhlpud.supabase.co/functions/v1/shop-data-api';
const INTERNAL_API_KEY = 'int_shopcall_YOUR_KEY_HERE';

async function fetchAllStores() {
  const response = await fetch(`${API_URL}/stores`, {
    headers: {
      'Authorization': `Bearer ${INTERNAL_API_KEY}`
    }
  });

  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const data = await response.json();
  return data;
}

async function fetchProducts(storeId, page = 1, limit = 25) {
  const response = await fetch(
    `${API_URL}/products?store_id=${storeId}&page=${page}&limit=${limit}`,
    {
      headers: {
        'Authorization': `Bearer ${INTERNAL_API_KEY}`
      }
    }
  );

  const data = await response.json();
  return data;
}
```

### Python Example

```python
import requests

API_URL = 'https://ztklqodcdjeqpsvhlpud.supabase.co/functions/v1/shop-data-api'
INTERNAL_API_KEY = 'int_shopcall_YOUR_KEY_HERE'

def fetch_all_stores():
    response = requests.get(
        f'{API_URL}/stores',
        headers={'Authorization': f'Bearer {INTERNAL_API_KEY}'}
    )
    response.raise_for_status()
    return response.json()

def fetch_products(store_id, page=1, limit=25):
    response = requests.get(
        f'{API_URL}/products',
        params={'store_id': store_id, 'page': page, 'limit': limit},
        headers={'Authorization': f'Bearer {INTERNAL_API_KEY}'}
    )
    response.raise_for_status()
    return response.json()
```

## Rate Limiting

- **Internal API Keys:** 200 requests/minute
- **User API Keys:** 100 requests/minute

Rate limit headers are included in responses:
```
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 195
X-RateLimit-Reset: 2025-01-31T17:01:00Z
```

## Error Responses

### 401 Unauthorized
```json
{
  "error": "Internal API key not found",
  "code": "NOT_FOUND",
  "timestamp": "2025-01-31T17:00:00Z"
}
```

### 429 Rate Limit Exceeded
```json
{
  "error": "Rate limit exceeded. Try again after 2025-01-31T17:01:00Z",
  "code": "RATE_LIMIT_EXCEEDED",
  "timestamp": "2025-01-31T17:00:00Z"
}
```

### 404 Store Not Found
```json
{
  "error": "Store not found or access denied",
  "code": "STORE_NOT_FOUND"
}
```

## Security Best Practices

1. **Store keys securely** - Never commit keys to version control
2. **Use environment variables** - Store keys in .env files
3. **Rotate keys regularly** - Create new keys and revoke old ones
4. **Set expiration dates** - Add `expires_at` for temporary access
5. **Monitor usage** - Check `last_used_at` for suspicious activity
6. **Limit key count** - Only create keys when necessary

## Management Functions

### Check Key Status

```sql
SELECT
  id,
  key_name,
  is_active,
  last_used_at,
  expires_at,
  created_at
FROM internal_api_keys
WHERE api_key = 'int_shopcall_YOUR_KEY';
```

### Revoke a Key

```sql
UPDATE internal_api_keys
SET is_active = false
WHERE id = 'key-uuid';

-- Or use helper function
SELECT revoke_internal_api_key('key-uuid');
```

### List Active Keys

```sql
SELECT
  id,
  key_name,
  description,
  created_by,
  last_used_at,
  created_at
FROM internal_api_keys
WHERE is_active = true
ORDER BY created_at DESC;
```

### Cleanup Expired Keys

```sql
-- Delete keys expired >30 days ago
SELECT cleanup_expired_internal_api_keys();
```

## Differences from User API Keys

| Feature | Internal API Keys | User API Keys |
|---------|------------------|---------------|
| Format | `int_shopcall_xxx` | `api_shopcall_xxx` |
| Access Scope | All webshops | User's webshops only |
| Rate Limit | 200 req/min | 100 req/min |
| UI Visibility | Hidden | Visible to users |
| Creation | Manual SQL | Via API endpoint |
| Management | Database only | User dashboard |
| Use Case | System integration | User applications |

## Migration Applied

Migration file: `supabase/migrations/20251031_170000_internal_api_keys_table.sql`

The migration creates:
- ✅ `internal_api_keys` table with RLS
- ✅ Helper functions for validation and management
- ✅ Triggers for timestamp updates
- ✅ Indexes for performance

## Related Files

- **Migration:** `supabase/migrations/20251031_170000_internal_api_keys_table.sql`
- **Auth Middleware:** `supabase/functions/_shared/internal-api-key-auth.ts`
- **API Endpoint:** `supabase/functions/shop-data-api/index.ts`

## Support

For issues or questions:
- Related Issue: #50
- Documentation: This file
- Contact: Development team

---

**Note:** Internal API keys are powerful! Only share them with trusted systems and services.
