# RetroSnap AI Photo Generation REST API Documentation
Version: `1.0.0`
Environment: `PHP 8.1+ / MySQLi / Apache`

Welcome to the **RetroSnap REST API Reference**. This API powers the RetroSnap native Android client, providing secure registration, credit transaction ledgers, active style listings, high-performance image editing, and failover-managed AI photo transformations.

---

## 🧭 Global Specifications

### Base URL
All API requests are routed through Apache rewrite wrappers to the Front Controller index routing:
`https://yourdomain.com/api/v1/`

### CORS & Security Headers
Every JSON output is locked down with strict security controls:
*   `Access-Control-Allow-Origin: *` (or specific client package origins)
*   `X-Frame-Options: DENY` (prevents clickjacking)
*   `X-Content-Type-Options: nosniff` (prevents MIME-type spoofing)
*   `Content-Type: application/json; charset=utf-8`

### Rate Limiting (Sliding Window)
*   **Default Rules**: 60 requests per 1-minute window per IP.
*   Enforced via hashing `SHA-256(IP + User-Agent)` in the `rate_limits` table.
*   **HTTP Header Outputs**:
    ```http
    X-RateLimit-Limit: 60
    X-RateLimit-Remaining: 47
    X-RateLimit-Reset: 1726823485
    ```
*   **Saturated Limit Exception**: Returns `HTTP 429 Too Many Requests` with envelope `{"success":false,"code":"RATE_LIMIT_EXCEEDED"}`.

### Standard Response Envelope
All responses return a JSON payload with a consistent structure:

#### Success Envelope (HTTP `200 OK` or `201 Created` or `202 Accepted`)
```json
{
  "success": true,
  "code": "SUCCESS",
  "message": "Styling instructions processed successfully.",
  "data": { ... }
}
```

#### Error Envelope (HTTP `400`, `401`, `402`, `403`, `404`, `429`, `500`)
```json
{
  "success": false,
  "code": "ERROR_CODE_IDENTIFIER",
  "message": "Human-readable descriptive issue statement."
}
```

---

## 🔒 Authentication Flow
RetroSnap uses secure **Google Sign-In Authentication** mapped to persistent Bearer Session tokens.

### Bearer Token Header
To access protected endpoints, include the session token in the authorization header:
```http
Authorization: Bearer <your_session_token_bytes>
```

---

## 📡 Endpoints Reference

### 1. Registration and Authentication

#### `POST /auth/firebase`
Exchange a Firebase ID token for a persistent session. Automatically registers new users.
*   **Request Parameters** (POST or JSON):
    *   `id_token` (string, required): The raw Firebase ID token returned from the client SDK.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Authentication successful.",
      "data": {
        "id": "usr_9f82de80...",
        "email": "user@gmail.com",
        "name": "Alex Carter",
        "credits": 10,
        "is_premium": false,
        "token": "9a38fdf8073b648db000c0ba10c9da1c6295982888cf30a11639d6cfbf4d528a"
      }
    }
    ```

#### `POST /auth/logout`
Invalidate and destroy the active bearer session.
*   **Authentication Required**: Yes.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Logged out successfully. Bearer token has been invalidated."
    }
    ```

#### `GET /me`
Retrieve the authenticated user's real-time profile, subscription state, and credit balance.
*   **Authentication Required**: Yes.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Profile fetched successfully.",
      "data": {
        "id": "usr_9f82de80...",
        "email": "user@gmail.com",
        "name": "Alex Carter",
        "credits": 150,
        "is_premium": true,
        "plan_expires_at": "2026-10-20 14:30:00"
      }
    }
    ```

#### `DELETE /account`
Permanently delete a user account (GDPR & Google Play compliant). Removes all original and edited images from disk, scrambles auth signatures, and deletes DB references.
*   **Authentication Required**: Yes.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Your profile, credits, and physical images have been permanently scrubbed."
    }
    ```

---

### 2. Style Catalogs & Feeds

#### `GET /home`
Fetch home feed items: active categories, trending styles, new releases, and global configurations.
*   **Authentication Required**: Yes.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Home feed successfully aggregated.",
      "data": {
        "user": {
          "id": "usr_9f82de80...",
          "name": "Alex Carter",
          "credits": 10,
          "is_premium": false,
          "plan_expires_at": null
        },
        "categories": [
          { "id": "80s_vibes", "name": "80s Vibes", "icon": "ic_80s" },
          { "id": "vintage_tech", "name": "Vintage Tech", "icon": "ic_crt" }
        ],
        "trending": [
          {
            "id": "style_80s_neon",
            "category_id": "80s_vibes",
            "title": "Neon Grid Portrait",
            "description": "Retro cyberpunk grid backdrop",
            "preview_image": "uploads/templates/neon_grid.jpg",
            "is_premium": false,
            "credit_cost": 2,
            "use_count": 1422
          }
        ],
        "new_releases": [ ... ],
        "config": {
          "maintenance_mode": false,
          "min_app_version_code": 1,
          "privacy_policy_url": "privacy-policy.html",
          "terms_url": "delete-account.html"
        }
      }
    }
    ```

#### `GET /templates`
Paginated search and category filtering for styles.
*   **Authentication Required**: Yes.
*   **Query Parameters**:
    *   `category_id` (string, optional): Filter by a specific category.
    *   `q` (string, optional): Fulltext keyword query matching titles or descriptions.
    *   `page` (int, optional, default 1): Page number.
    *   `per_page` (int, optional, default 10): Items per page.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Templates fetched successfully.",
      "data": {
        "templates": [ ... ],
        "pagination": {
          "total_items": 12,
          "current_page": 1,
          "per_page": 10,
          "total_pages": 2
        }
      }
    }
    ```

#### `GET /templates/{id}`
Retrieve details for a specific style template and recommend similar styles in the same category.
*   **Authentication Required**: Yes.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Style details fetched.",
      "data": {
        "id": "style_80s_neon",
        "category_id": "80s_vibes",
        "title": "Neon Grid Portrait",
        "description": "Retro cyberpunk grid backdrop",
        "preview_image": "uploads/templates/neon_grid.jpg",
        "sample_outputs": [
          "uploads/templates/samples/neon_out1.jpg",
          "uploads/templates/samples/neon_out2.jpg"
        ],
        "is_premium": false,
        "is_trending": true,
        "credit_cost": 2,
        "prompt_text": "Convert photo to portrait of person against neon grids...",
        "created_at": "2026-09-18 10:00:00",
        "similar_templates": [ ... ]
      }
    }
    ```

---

### 3. Generation & Editing

#### `POST /generate`
Submit an image and apply a style template. **Supports Idempotency keys** to prevent duplicate credit charges on network retries.
*   **Authentication Required**: Yes.
*   **Headers**:
    *   `Idempotency-Key` (string, highly recommended): Unique UUID generated by the client app.
*   **Request Parameters** (`multipart/form-data`):
    *   `template_id` (string, required): Target template ID.
    *   `image` (file upload, required): Source JPEG, PNG, or WEBP file (max 8MB).
    *   `user_prompt` (string, optional): Additional text adjustments (max 250 chars).
    *   `strength` (int, optional, 0-100, default 100): Stylization intensity.
*   **Success Response** (HTTP `200` or `202` if duplicate is already processing):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Retro photo generated successfully.",
      "data": {
        "generation_id": "gen_8e29a91c-22a0...",
        "output_url": "media/generated/gen_8e29a91c-22a0...",
        "status": "success",
        "remaining_credits": 8
      }
    }
    ```

#### `POST /edited`
Save cropped, rotated, or manually edited versions of images.
*   **Authentication Required**: Yes.
*   **Request Parameters** (`multipart/form-data`):
    *   `edited_image` (file upload, required): The modified image.
    *   `generation_id` (string, optional): Links the edited version to its parent AI generation.
    *   `edit_meta` (JSON string, optional): Crop matrices, rotations, or filter levels.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Edited image saved successfully.",
      "data": {
        "edited_id": "edt_f02ca19...",
        "output_url": "media/edited/edt_f02ca19..."
      }
    }
    ```

#### `GET /generations`
Fetch paginated user creations, edits, or favorites.
*   **Authentication Required**: Yes.
*   **Query Parameters**:
    *   `tab` (string, optional, default 'generated'): Must be `'generated'`, `'edited'`, or `'favorites'`.
    *   `page` (int, optional, default 1)
    *   `per_page` (int, optional, default 10)
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Paging history fetched successfully.",
      "data": {
        "tab": "generated",
        "items": [
          {
            "id": "gen_8e29a91c-22a0...",
            "template_id": "style_80s_neon",
            "template_title": "Neon Grid Portrait",
            "status": "success",
            "credits_used": 2,
            "output_url": "media/generated/gen_8e29a91c-22a0...",
            "created_at": "2026-09-20 02:00:00"
          }
        ],
        "pagination": { ... }
      }
    }
    ```

#### `GET /generations/{id}`
Retrieve details for a specific generation.
*   **Authentication Required**: Yes.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Generation details successfully retrieved.",
      "data": {
        "id": "gen_8e29a91c-22a0...",
        "template_id": "style_80s_neon",
        "template_title": "Neon Grid Portrait",
        "template_preview": "uploads/templates/neon_grid.jpg",
        "input_url": "media/user_uploads/gen_8e29a91c-22a0...",
        "output_url": "media/generated/gen_8e29a91c-22a0...",
        "user_prompt": "smiling, neon grids",
        "strength": 100,
        "status": "success",
        "credits_used": 2,
        "error_message": null,
        "duration_ms": 4120,
        "is_favorited": true,
        "created_at": "2026-09-20 02:00:00"
      }
    }
    ```

#### `DELETE /generations/{id}`
Permanently delete a user-generated photo and its source files from the storage disk.
*   **Authentication Required**: Yes.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Retro generation record and files have been permanently deleted."
    }
    ```

#### `POST /favorites/toggle`
Favorite or unfavorite an AI-generated photo.
*   **Authentication Required**: Yes.
*   **Request Parameters** (POST or JSON):
    *   `generation_id` (string, required): The target generation ID.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Added photo to favorites.",
      "data": { "is_favorited": true }
    }
    ```

#### `POST /report`
Flag or report inappropriate content in a generated photo.
*   **Authentication Required**: Yes.
*   **Request Parameters** (POST or JSON):
    *   `generation_id` (string, required): The target generation ID.
    *   `reason` (string, required): e.g., `'nsfw'`, `'violence'`, `'hate'`, `'copyright'`.
    *   `note` (string, optional): Additional details for review (max 500 chars).
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Content report submitted successfully. Our security team will review it shortly."
    }
    ```

---

### 4. Billing, Subscriptions & System

#### `GET /plans`
Retrieve a list of active subscription tiers.
*   **Authentication Required**: Yes.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Active subscription tiers fetched successfully.",
      "data": [
        {
          "id": "plan_silver",
          "name": "Silver Premium",
          "google_product_id": "com.retrosnap.sub.silver",
          "credits": 200,
          "watermark_free": true,
          "period_days": 30
        }
      ]
    }
    ```

#### `POST /subscription/verify`
Verify a Google Play purchase token. On success, grants benefits, adds credits to balance, and registers the subscription.
*   **Authentication Required**: Yes.
*   **Request Parameters** (POST or JSON):
    *   `purchase_token` (string, required): The billing purchase token from Google Play.
    *   `product_id` (string, required): The corresponding product ID.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Subscription verified and credited successfully.",
      "data": {
        "plan_name": "Silver Premium",
        "credits_granted": 200,
        "new_balance": 200,
        "expires_at": "2026-10-20 02:15:00"
      }
    }
    ```

#### `POST /fcm-token`
Register or update the user's Firebase Cloud Messaging token for push notifications.
*   **Authentication Required**: Yes.
*   **Request Parameters** (POST or JSON):
    *   `fcm_token` (string, required): The FCM push token from the client SDK.
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "FCM notification token registered successfully."
    }
    ```

#### `POST /play/webhook`
Google Play Developer Cloud Pub/Sub push notification endpoint. Handles real-time events: renewed, canceled, grace, onhold, expired, revoked.
*   **Authentication Required**: Public (validated via Google envelope signatures).
*   **Success Response** (HTTP `200`):
    ```json
    {
      "success": true,
      "code": "SUCCESS",
      "message": "Webhook processed successfully."
    }
    ```

---

### 🛡️ 5. Private Media Streamer

#### `GET /media/{type}/{id}`
Securely streams private images stored outside the web root (`/private/storage`).
*   **Authentication Required**: Yes (enforces caller ownership validation).
*   **Path Parameters**:
    *   `type` (string): Must be `'user_uploads'`, `'generated'`, or `'edited'`.
    *   `id` (string): Database record ID.
*   **Security Actions**:
    1.  Validates the session token.
    2.  Verifies the authenticated user owns the requested image record.
    3.  Sanitizes the file path using `realpath` matches to block directory traversal attacks.
    4.  Determines MIME type dynamically and streams bytes with optimized cache-control headers.

---

## 🛠️ CLI Administration & Verification Tools

These tools must be run from a terminal inside the private server directory (`/private`). They should never be exposed to the public web root.

### 1. Cryptographic AES-256-GCM Master Key Generator
Generate a secure Base64 key to define in `config.php`:
```bash
php /private/tools/generate_master_key.php
```

### 2. Third-Party API Credentials Encryptor
Encrypt API keys before inserting them into your MySQL `providers` table:
```bash
php /private/tools/encrypt_key.php "your_raw_api_key_string"
```

### 3. Provider Connection Tester
Validate connections and generate a test image using active provider credentials directly from the command line:
```bash
php /private/tools/test_provider.php gemini_active
```
*Creates a mock image, passes it to the provider, validates the response, and saves the output to `/private/storage` to verify end-to-end functionality.*

### 4. Background Server Maintenance Cron
Run daily cron tasks to reset provider limits, process subscription expiries, and refill free credits:
```bash
php /private/cron/reset_daily.php
```

### 5. Automated Storage Cleanup Cron
Flush sliding window logs and clean up stale temporary files:
```bash
php /private/cron/cleanup.php
```

---

## 🚫 Error Codes Guide

| Code | HTTP Status | Description |
| :--- | :--- | :--- |
| `SUCCESS` | 200 | Request completed successfully. |
| `VALIDATION_ERROR` | 400 | Missing parameter, invalid range, or malformed input. |
| `INVALID_TOKEN` | 401 / 403 | Invalid session, expired token, or unauthorized file access. |
| `NO_CREDITS` | 402 | User credit balance is lower than the style template's cost. |
| `PREMIUM_REQUIRED` | 403 | Attempting to use a Premium style template with a Free account. |
| `NOT_FOUND` | 404 | Record, template, or physical file does not exist. |
| `CONTENT_BLOCKED` | 400 | Prompt text violates safety policies (NSFW, violence, etc.). |
| `DAILY_LIMIT` | 429 | User has exceeded their daily styled photo generation limit. |
| `RATE_LIMIT_EXCEEDED` | 429 | Global sliding window rate limit reached (max 60 req/min). |
| `PROVIDER_UNAVAILABLE`| 503 | Remote AI providers are over capacity. Credits are fully refunded. |
| `SERVER_ERROR` | 500 | Internal database exception or file system writing error. |
