# BERNIE Store — Frontend API Reference

Complete API documentation for frontend integration.

**Base URL:** `http://localhost:8000/api`  
**Content-Type:** `application/json` (unless uploading files — use `multipart/form-data`)

---

## Table of Contents

1. [Quick Reference](#quick-reference)
2. [Authentication & Sessions](#authentication--sessions)
3. [Products](#products)
4. [Categories](#categories)
5. [Sections](#sections)
6. [Cart](#cart)
7. [Basket](#basket)
8. [Checkout & Orders](#checkout--orders)
9. [Coupons](#coupons)
10. [Delivery & Shipments](#delivery--shipments)
11. [Payment Gateways](#payment-gateways)
12. [Media](#media)
13. [Wishlist](#wishlist)
14. [Product Reviews](#product-reviews)
15. [Price Alerts](#price-alerts)
16. [Back-in-Stock Alerts](#back-in-stock-alerts)
17. [Referral Program](#referral-program)
18. [Reward Points](#reward-points)
19. [Customer Wallet](#customer-wallet)
20. [VIP Membership](#vip-membership)
21. [Member Pricing](#member-pricing)
22. [Promotions & Deals](#promotions--deals)
23. [Multi-Currency](#multi-currency)
24. [Language & Translations](#language--translations)
25. [SEO](#seo)
26. [Product Sharing](#product-sharing)
27. [Special Pages](#special-pages)
28. [Frontend Integration Guide](#frontend-integration-guide)

---

## Quick Reference

| Method | Endpoint | Auth | Description |
|--------|----------|------|-------------|
| **Auth** |
| POST | `/api/auth/login` | None | Customer login |
| POST | `/api/auth/register` | None | Customer register |
| POST | `/api/auth/logout` | Bearer token | Logout |
| GET | `/api/auth/me` | Bearer token | Get current customer |
| **Products** |
| GET | `/api/products` | None | List products |
| GET | `/api/products/trending` | None | Trending products |
| GET | `/api/products/search?q=` | None | Search products |
| GET | `/api/products/suggestions?q=` | None | Search suggestions |
| GET | `/api/products/{slug}` | None | Get product by slug |
| GET | `/api/products/{slug}/related` | None | Related products |
| GET | `/api/products/{slug}/share` | None | Share links |
| POST | `/api/products` | Admin | Create product |
| PUT | `/api/products/{id}` | Admin | Update product |
| DELETE | `/api/products/{id}` | Admin | Delete product |
| **Categories** |
| GET | `/api/categories` | None | List categories |
| GET | `/api/categories/{slug}` | None | Get category |
| POST | `/api/categories` | None | Create category |
| PUT | `/api/categories/{id}` | None | Update category |
| DELETE | `/api/categories/{id}` | None | Delete category |
| **Sections** |
| GET | `/api/sections` | None | List sections |
| GET | `/api/sections/{key}` | None | Get section by key |
| POST | `/api/sections` | None | Create section |
| PUT | `/api/sections/{id}` | None | Update section |
| DELETE | `/api/sections/{id}` | None | Delete section |
| **Cart** |
| GET | `/api/cart` | Session | Get cart items |
| GET | `/api/cart/summary` | Session | Cart totals |
| POST | `/api/cart` | Session | Add item |
| POST | `/api/cart/sync` | Session | Sync cart from local |
| PUT | `/api/cart/{id}` | Session | Update quantity |
| DELETE | `/api/cart/{id}` | Session | Remove item |
| DELETE | `/api/cart` | Session | Clear cart |
| **Basket** |
| GET | `/api/basket` | Session | Get basket |
| POST | `/api/basket` | Session | Add item |
| PUT | `/api/basket/{id}` | Session | Update quantity |
| DELETE | `/api/basket/{id}` | Session | Remove item |
| DELETE | `/api/basket` | Session | Clear basket |
| **Checkout & Orders** |
| GET | `/api/checkout/payment-methods` | None | Payment methods |
| POST | `/api/checkout/preview` | Session | Preview checkout totals |
| GET | `/api/orders` | Session | List session orders |
| POST | `/api/orders` | Session | Create order |
| GET | `/api/orders/{id}` | None | Get order |
| POST | `/api/orders/{id}/pay` | None | Pay order |
| POST | `/api/orders/{id}/reorder` | Session | Reorder |
| **Coupons** |
| GET | `/api/coupons/claim/{type}` | None | Claim coupon |
| POST | `/api/coupons/validate` | Session | Validate coupon |
| **Delivery** |
| GET | `/api/delivery/zones` | None | Delivery zones |
| POST | `/api/delivery/check` | None | Check postal code |
| POST | `/api/shipments/track` | None | Track shipment |
| **Payment Gateways** |
| GET | `/api/gateways` | None | Active gateways |
| **Media** |
| GET | `/api/media` | None | List media |
| POST | `/api/media` | None | Upload file |
| GET | `/api/media/{id}` | None | Get media |
| DELETE | `/api/media/{id}` | None | Delete media |
| **Wishlist** |
| GET | `/api/wishlist` | Session | Get wishlist |
| POST | `/api/wishlist` | Session | Add to wishlist |
| DELETE | `/api/wishlist/{id}` | Session | Remove item |
| POST | `/api/wishlist/{productId}/move-to-cart` | Session | Move to cart |
| **Reviews** |
| GET | `/api/reviews` | Session | My reviews |
| POST | `/api/reviews` | Session | Submit review |
| GET | `/api/reviews/product/{productId}` | None | Product reviews |
| **Price Alerts** |
| GET | `/api/price-alerts` | Session | My alerts |
| POST | `/api/price-alerts` | Session | Create alert |
| DELETE | `/api/price-alerts/{id}` | Session | Delete alert |
| **Back-in-Stock** |
| GET | `/api/back-in-stock` | Session | My subscriptions |
| POST | `/api/back-in-stock` | Session | Subscribe |
| DELETE | `/api/back-in-stock/{id}` | Session | Unsubscribe |
| **Referrals** |
| GET | `/api/referrals` | Session | My referral codes |
| POST | `/api/referrals/generate` | Session | Generate code |
| POST | `/api/referrals/redeem` | Session | Redeem code |
| **Rewards** |
| GET | `/api/rewards/balance` | Session | Points balance |
| GET | `/api/rewards/history` | Session | Points history |
| POST | `/api/rewards/redeem` | Session | Redeem points |
| GET | `/api/rewards/settings` | None | Reward settings |
| **Wallet** |
| GET | `/api/wallet` | Session | Wallet details |
| GET | `/api/wallet/balance` | Session | Wallet balance |
| GET | `/api/wallet/history` | Session | Transaction history |
| **VIP** |
| GET | `/api/vip/status` | Session | VIP status |
| POST | `/api/vip/upgrade` | Session | Upgrade tier |
| **Member Pricing** |
| GET | `/api/member-prices` | None | All member prices |
| GET | `/api/member-prices/product/{productId}` | None | Prices for product |
| POST | `/api/member-prices` | None | Create price |
| PUT | `/api/member-prices/{id}` | None | Update price |
| DELETE | `/api/member-prices/{id}` | None | Delete price |
| **Promotions** |
| GET | `/api/order-value-promotions` | None | Order value promos |
| GET | `/api/quantity-promotions` | None | Quantity promos |
| GET | `/api/quantity-promotions/product/{productId}` | None | Product quantity promo |
| GET | `/api/daily-deals` | None | Daily deals |
| GET | `/api/daily-deals/product/{productId}` | None | Product daily deal |
| GET | `/api/weekly-specials` | None | Weekly specials |
| GET | `/api/save-the-food` | None | Save The Food page |
| **Currency** |
| GET | `/api/currencies` | None | Active currencies |
| POST | `/api/currencies/switch` | Session | Switch currency |
| POST | `/api/currencies/convert` | None | Convert amount |
| **Language** |
| GET | `/api/languages` | None | Active languages |
| GET | `/api/languages/{code}` | None | Get language |
| POST | `/api/languages/switch` | Session | Switch language |
| GET | `/api/translations/{locale}` | None | Get translations |
| **SEO** |
| GET | `/api/seo/products/{slug}` | None | Product SEO meta |
| GET | `/api/seo/categories/{slug}` | None | Category SEO meta |

---

## Authentication & Sessions

The API uses **two auth modes**:

| Mode | Used for | How |
|------|----------|-----|
| **Session (cookies)** | Cart, basket, orders, wishlist, wallet, rewards, referrals, VIP | Send cookies with every request (`credentials: "include"`) |
| **Bearer token (Sanctum)** | Customer login/register/logout/me | `Authorization: Bearer {token}` |

### POST `/api/auth/login`

**Request:**
```json
{
  "email": "customer@example.com",
  "password": "password123"
}
```

**Response `200`:**
```json
{
  "success": true,
  "message": "Login successful.",
  "data": {
    "customer": {
      "id": 1,
      "name": "John Doe",
      "email": "customer@example.com",
      "phone": null,
      "is_active": true
    },
    "token": "1|abc123..."
  }
}
```

---

### POST `/api/auth/register`

**Request:**
```json
{
  "name": "John Doe",
  "email": "customer@example.com",
  "password": "password123",
  "password_confirmation": "password123",
  "phone": "+49123456789"
}
```

**Response `201`:** Same shape as login.

---

### GET `/api/auth/me`

**Headers:** `Authorization: Bearer {token}`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "id": 1,
    "name": "John Doe",
    "email": "customer@example.com",
    "phone": null,
    "is_active": true
  }
}
```

---

### POST `/api/auth/logout`

**Headers:** `Authorization: Bearer {token}`

**Response `200`:**
```json
{
  "success": true,
  "message": "Logged out successfully."
}
```

---

## Products

### GET `/api/products`

**Query params (all optional):**

| Param | Type | Description |
|-------|------|-------------|
| `category` | string | Filter by category slug |
| `brand` | string | Filter by brand |
| `sort` | string | Sort order |
| `tags` | string/array | Filter by tags |
| `search` | string | Search term |
| `per_page` | int | Pagination size |

**Response `200`:**
```json
{
  "data": [
    {
      "id": 1,
      "name": "Organic Bananas",
      "slug": "organic-bananas",
      "description": "Fresh organic bananas.",
      "price": 2.99,
      "unit": "bunch",
      "unit_price": 0.3,
      "image_url": "http://localhost:8000/storage/media/products/bananas.jpg",
      "brand": null,
      "discount": 10,
      "original_price": 3.32,
      "final_price": 2.69,
      "is_on_sale": true,
      "nutri_score": "A",
      "tags": ["organic", "fruit"],
      "nutrition": null,
      "preparation": null,
      "ingredients": null,
      "allergens_info": null,
      "stock_quantity": 50,
      "min_order_quantity": 1,
      "max_order_quantity": null,
      "is_active": true,
      "is_save_the_food": false,
      "is_weekly_special": true,
      "category_id": 1,
      "category": {
        "id": 1,
        "name": "Obst & Gemüse",
        "slug": "obst-gemuese",
        "icon": "apple",
        "image_url": null
      },
      "media": [
        {
          "id": 1,
          "url": "http://localhost:8000/storage/media/products/bananas.jpg",
          "filename": "bananas.jpg",
          "mime_type": "image/jpeg"
        }
      ],
      "created_at": "2026-05-24T10:00:00.000000Z",
      "updated_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### GET `/api/products/trending`

Returns top 10 trending products. Same response shape as list.

---

### GET `/api/products/search?q=banana`

**Query:** `q` (string, optional)

**Response `200`:** `{ "data": [ ...products ] }`

---

### GET `/api/products/suggestions?q=ban`

**Query:** `q` (string, optional)

**Response `200`:** `{ "data": [ ...products ] }`

---

### GET `/api/products/{slug}`

**Response `200`:** `{ "data": { ...single product } }`

---

### GET `/api/products/{slug}/related`

**Response `200`:** `{ "data": [ ...related products ] }`

---

### POST `/api/products` — Admin only

**Auth:** Admin session (`auth:web`)

**Request (multipart/form-data or JSON):**

| Field | Type | Required |
|-------|------|----------|
| `name` | string | yes |
| `slug` | string | yes |
| `price` | numeric ≥ 0 | yes |
| `description` | string | no |
| `unit` | string | no |
| `unit_price` | numeric | no |
| `image` | file (jpg/png/gif/webp/svg, max 2MB) | no |
| `category_id` | int | no |
| `brand` | string | no |
| `discount` | numeric 0–100 | no |
| `original_price` | numeric | no |
| `tags` | array | no |
| `nutrition` | array | no |
| `nutri_score` | string | no |
| `ingredients` | string | no |
| `is_save_the_food` | boolean | no |
| `is_weekly_special` | boolean | no |

**Response `201`:** `{ "data": { ...product } }`

---

### PUT `/api/products/{id}` — Admin only

Same fields as POST (all optional on update).

**Response `200`:** `{ "data": { ...product } }`

---

### DELETE `/api/products/{id}` — Admin only

**Response `204`:** No content.

---

## Categories

### GET `/api/categories`

**Response `200`:**
```json
{
  "data": [
    {
      "id": 1,
      "name": "Obst & Gemüse",
      "slug": "obst-gemuese",
      "icon": "apple",
      "description": null,
      "image_url": null,
      "sort_order": 1,
      "is_active": true,
      "media": [],
      "created_at": "2026-05-24T10:00:00.000000Z",
      "updated_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### GET `/api/categories/{slug}`

**Response `200`:** `{ "data": { ...category } }`

---

### POST `/api/categories`

**Request:**

| Field | Type | Required |
|-------|------|----------|
| `name` | string | yes |
| `slug` | string | yes |
| `icon` | string | no |
| `description` | string | no |
| `image` | file | no |
| `sort_order` | int | no |
| `is_active` | boolean | no |

**Response `201`:** `{ "data": { ...category } }`

---

### PUT `/api/categories/{id}`

Same fields as POST.

**Response `200`:** `{ "data": { ...category } }`

---

### DELETE `/api/categories/{id}`

**Response `204`:** No content.

---

## Sections

### GET `/api/sections`

**Response `200`:**
```json
[
  {
    "id": 1,
    "key": "hero",
    "title": "Fresh From Local Farmers",
    "subtitle": "Summer Seasonal",
    "description": "Direct delivery to your doorstep.",
    "image_url": "https://...",
    "button_text": "Shop Harvest",
    "button_link": "/categories",
    "badge_text": "Summer Seasonal",
    "sort_order": 1,
    "is_active": true,
    "metadata": null,
    "created_at": "2026-05-24T10:00:00.000000Z",
    "updated_at": "2026-05-24T10:00:00.000000Z"
  }
]
```

---

### GET `/api/sections/{key}`

Example keys: `hero`, `save-the-food`, `trending`

**Response `200`:** Single section object (no `data` wrapper).

---

### POST `/api/sections`

**Request:**

| Field | Type | Required |
|-------|------|----------|
| `key` | string | yes |
| `title` | string | yes |
| `subtitle` | string | no |
| `description` | string | no |
| `image` | file | no |
| `button_text` | string | no |
| `button_link` | string | no |
| `badge_text` | string | no |
| `sort_order` | int | no |
| `is_active` | boolean | no |
| `metadata` | JSON object | no |

---

## Cart

All cart endpoints require **session cookies**.

### GET `/api/cart`

**Response `200`:**
```json
{
  "data": [
    {
      "id": 1,
      "product_id": 1,
      "product_name": "Organic Bananas",
      "price": 2.99,
      "unit": "bunch",
      "unit_price": 0.3,
      "image_url": "http://localhost:8000/storage/...",
      "quantity": 2,
      "note": null,
      "created_at": "2026-05-24T10:00:00.000000Z",
      "updated_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### GET `/api/cart/summary`

**Response `200`:**
```json
{
  "items": [ ... ],
  "subtotal": 5.98,
  "delivery_fee": 0,
  "service_fee": 0,
  "total": 5.98,
  "count": 2
}
```

---

### POST `/api/cart`

**Request:**
```json
{
  "product_id": 1,
  "product_name": "Organic Bananas",
  "price": 2.99,
  "quantity": 2,
  "unit": "bunch",
  "unit_price": 0.3,
  "image_url": "http://localhost:8000/storage/...",
  "note": "Ripe please"
}
```

| Field | Type | Required |
|-------|------|----------|
| `product_id` | int or slug string | yes |
| `product_name` | string | yes |
| `price` | numeric | yes |
| `quantity` | int ≥ 1 | no (default 1) |
| `unit` | string | no |
| `unit_price` | numeric | no |
| `image_url` | string | no |
| `note` | string | no |

**Response `201`:** Updated cart item.

---

### POST `/api/cart/sync`

Sync local cart state to server (useful on page load).

**Request:**
```json
{
  "items": [
    {
      "product_id": 1,
      "product_name": "Organic Bananas",
      "price": 2.99,
      "quantity": 2,
      "unit": "bunch",
      "unit_price": 0.3,
      "image_url": "http://localhost:8000/storage/..."
    }
  ]
}
```

**Response `200`:** Full synced cart.

---

### PUT `/api/cart/{id}`

**Request:**
```json
{ "quantity": 3 }
```

**Response `200`:** Updated cart item.

---

### DELETE `/api/cart/{id}`

**Response `204`:** No content.

---

### DELETE `/api/cart`

Clear entire cart.

**Response `204`:** No content.

---

## Basket

Checkout basket — same session auth as cart.

### GET `/api/basket`

**Response `200`:**
```json
{
  "items": [ ... ],
  "subtotal": 5.98,
  "delivery_fee": 3.99,
  "service_fee": 0.50,
  "total": 10.47,
  "vat_amount": 0.84,
  "item_count": 2
}
```

---

### POST `/api/basket`

**Request:** Same as cart add (product_id must be integer).

**Response `201`:** Updated basket.

---

### PUT `/api/basket/{id}`

**Request:**
```json
{ "quantity": 0 }
```

Setting `quantity` to `0` removes the item.

**Response `200`:** Updated item, or `204` if removed.

---

### DELETE `/api/basket/{id}`

**Response `204`:** No content.

---

### DELETE `/api/basket`

**Response `204`:** No content.

---

## Checkout & Orders

### GET `/api/checkout/payment-methods`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "Credit Card",
      "code": "credit_card",
      "is_active": true
    }
  ]
}
```

---

### POST `/api/checkout/preview`

Calculate totals before placing order (coupons, points, wallet, delivery).

**Request:**
```json
{
  "items": [
    {
      "product_id": 1,
      "product_name": "Organic Bananas",
      "price": 2.99,
      "quantity": 2,
      "unit": "bunch"
    }
  ],
  "coupon_code": "SAVE10",
  "referral_code": "REF123",
  "points_to_redeem": 100,
  "wallet_amount": 5.00,
  "postal_code": "10115"
}
```

| Field | Type | Required |
|-------|------|----------|
| `items` | array (min 1) | yes |
| `items.*.product_id` | int or slug | yes |
| `items.*.product_name` | string | yes |
| `items.*.price` | numeric ≥ 0 | yes |
| `items.*.quantity` | int ≥ 1 | yes |
| `items.*.unit` | string | no |
| `coupon_code` | string | no |
| `referral_code` | string | no |
| `points_to_redeem` | int ≥ 0 | no |
| `wallet_amount` | numeric ≥ 0 | no |
| `postal_code` | string | no |

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "items": [ ... ],
    "subtotal": 8.48,
    "delivery_fee": 3.99,
    "service_fee": 0.50,
    "discount_amount": 1.00,
    "loyalty_discount": 0,
    "wallet_amount": 0,
    "points_used": 0,
    "vat_amount": 0.68,
    "total": 12.97,
    "coupon_code": null,
    "coupon_id": null,
    "referral_code": null,
    "delivery_zone_id": 1,
    "free_shipping": false,
    "breakdown": {
      "order_promo_discount": 0,
      "coupon_discount": 0,
      "vip_discount": 0,
      "referral_discount": 0
    }
  }
}
```

---

### GET `/api/orders`

List all orders for current session.

**Response `200`:**
```json
{
  "success": true,
  "data": [ ...orders ]
}
```

---

### POST `/api/orders`

**Request:**
```json
{
  "items": [
    {
      "product_id": 1,
      "product_name": "Organic Bananas",
      "price": 2.99,
      "quantity": 2
    }
  ],
  "customer_email": "customer@example.com",
  "coupon_code": "SAVE10",
  "referral_code": "REF123",
  "points_to_redeem": 100,
  "wallet_amount": 5.00,
  "postal_code": "10115",
  "notes": "Leave at door"
}
```

**Response `201`:**
```json
{
  "success": true,
  "data": {
    "id": 1,
    "order_number": "BRN-ORD-001",
    "status": "pending",
    "payment_status": "pending",
    "payment_method": null,
    "subtotal": 8.48,
    "delivery_fee": 3.99,
    "service_fee": 0.50,
    "discount_amount": 1.00,
    "total": 12.97,
    "vat_amount": 0.68,
    "notes": "Leave at door",
    "items": [
      {
        "product_id": 1,
        "product_name": "Organic Bananas",
        "price": 2.99,
        "quantity": 2,
        "subtotal": 5.98
      }
    ],
    "created_at": "2026-05-24T10:00:00.000000Z",
    "updated_at": "2026-05-24T10:00:00.000000Z"
  }
}
```

**Order statuses:** `pending` | `confirmed` | `processing` | `shipped` | `delivered` | `cancelled`  
**Payment statuses:** `pending` | `paid` | `failed` | `refunded`

---

### GET `/api/orders/{id}`

**Response `200`:** `{ "success": true, "data": { ...order with items } }`  
**Response `404`:** `{ "success": false, "message": "Order not found" }`

---

### POST `/api/orders/{id}/pay`

**Request:**
```json
{
  "payment_method": "credit_card",
  "payment_token": "tok_abc123"
}
```

| Field | Type | Required |
|-------|------|----------|
| `payment_method` | string | yes |
| `payment_token` | string | no |

**Response `200`:** `{ "success": true, "data": { ...updated order } }`  
**Response `422`:** `{ "success": false, "message": "Payment failed reason" }`

---

### POST `/api/orders/{id}/reorder`

**Request:**
```json
{ "session_id": "optional-session-id" }
```

**Response `200`:** `{ "success": true, "data": { ...reorder result } }`

---

## Coupons

### GET `/api/coupons/claim/{type}`

**Path `{type}`:** `new_client` | `vip` | `happy` | `first_order`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "id": 1,
    "code": "WELCOME10",
    "discount_type": "percentage",
    "discount_value": 10,
    "expires_at": "2026-12-31T23:59:59.000000Z"
  }
}
```

---

### POST `/api/coupons/validate`

**Request:**
```json
{
  "code": "SAVE10",
  "order_total": 50.00
}
```

**Response (valid):**
```json
{
  "success": true,
  "valid": true,
  "coupon": { ... },
  "discount": 5.00,
  "free_shipping": false,
  "discount_type": "percentage",
  "discount_value": 10,
  "message": "Coupon applied successfully!"
}
```

**Response (invalid):**
```json
{
  "success": false,
  "valid": false,
  "message": "Invalid or expired coupon."
}
```

---

## Delivery & Shipments

### GET `/api/delivery/zones`

**Response `200`:** Array of delivery zones with areas and fees.

---

### POST `/api/delivery/check`

**Request:**
```json
{ "postal_code": "10115" }
```

**Response (available):**
```json
{
  "available": true,
  "zone": { "id": 1, "name": "Berlin", "delivery_fee": 3.99 },
  "area": { "id": 1, "postal_code": "10115", "city": "Berlin" },
  "delivery_fee": 3.99,
  "min_order_amount": 25.00,
  "estimated_days": 2
}
```

**Response (not available):**
```json
{
  "available": false,
  "message": "Delivery not available for this postal code."
}
```

---

### POST `/api/shipments/track`

**Request:**
```json
{ "tracking_number": "BRN-TRK-001234" }
```

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "tracking_number": "BRN-TRK-001234",
    "carrier": "DHL",
    "status": "in_transit",
    "shipped_at": "2026-05-24T10:00:00.000000Z",
    "delivered_at": null,
    "order_id": 1
  }
}
```

---

## Payment Gateways

### GET `/api/gateways`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "name": "Stripe",
      "code": "stripe",
      "is_active": true,
      "config": { ... }
    }
  ]
}
```

---

## Media

### GET `/api/media`

**Response `200`:** List of media files.

---

### POST `/api/media`

**Request (multipart/form-data):**

| Field | Type | Required |
|-------|------|----------|
| `file` | file | yes |
| `type` | string (`image`/`file`/`video`) | no |
| `mediable_type` | string | no |
| `mediable_id` | int | no |

**Response `201`:**
```json
{
  "id": 1,
  "url": "http://localhost:8000/storage/media/products/abc123.jpg",
  "filename": "bananas.jpg",
  "mime_type": "image/jpeg",
  "size": 102400
}
```

---

### GET `/api/media/{id}`

**Response `200`:** Single media object.

---

### DELETE `/api/media/{id}`

**Response `204`:** No content.

---

## Wishlist

### GET `/api/wishlist`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "session_id": "...",
      "product_id": 1,
      "product": { ...product object },
      "created_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### POST `/api/wishlist`

**Request:**
```json
{ "product_id": 1 }
```

**Response `201`:**
```json
{
  "success": true,
  "data": { ...wishlist item },
  "message": "Product added to wishlist."
}
```

---

### DELETE `/api/wishlist/{id}`

**Response `200`:** `{ "success": true, "message": "Product removed from wishlist." }`

---

### POST `/api/wishlist/{productId}/move-to-cart`

**Response `200`:** `{ "success": true, "data": { ...cart result } }`

---

## Product Reviews

### GET `/api/reviews`

Returns reviews submitted by current session.

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "product_id": 1,
      "rating": 5,
      "title": "Great product!",
      "body": "Very fresh and tasty.",
      "is_approved": true,
      "created_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### POST `/api/reviews`

**Request:**
```json
{
  "product_id": 1,
  "rating": 5,
  "title": "Great product!",
  "body": "Very fresh and tasty."
}
```

| Field | Type | Required |
|-------|------|----------|
| `product_id` | int | yes |
| `rating` | int 1–5 | yes |
| `title` | string | no |
| `body` | string | no |

**Response `201`:** `{ "success": true, "data": { ...review }, "message": "Review submitted successfully." }`

---

### GET `/api/reviews/product/{productId}`

**Response `200`:** `{ "success": true, "data": [ ...approved reviews ] }`

---

## Price Alerts

### GET `/api/price-alerts`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "product_id": 1,
      "desired_price": 2.00,
      "product": { ... },
      "created_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### POST `/api/price-alerts`

**Request:**
```json
{
  "product_id": 1,
  "desired_price": 2.00
}
```

**Response `201`:** `{ "success": true, "data": { ...alert }, "message": "Price alert created." }`

---

### DELETE `/api/price-alerts/{id}`

**Response `200`:** `{ "success": true, "message": "Price alert removed." }`

---

## Back-in-Stock Alerts

### GET `/api/back-in-stock`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "product_id": 1,
      "email": "customer@example.com",
      "product": { ... },
      "created_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### POST `/api/back-in-stock`

**Request:**
```json
{
  "product_id": 1,
  "email": "customer@example.com"
}
```

| Field | Type | Required |
|-------|------|----------|
| `product_id` | int | yes |
| `email` | string (email) | no |

**Response `201`:** `{ "success": true, "data": { ...alert } }`

---

### DELETE `/api/back-in-stock/{id}`

**Response `200`:** `{ "success": true, "message": "Unsubscribed." }`

---

## Referral Program

### GET `/api/referrals`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "code": "REF-ABC123",
      "discount_percent": 10,
      "is_used": false,
      "expires_at": "2026-12-31T23:59:59.000000Z",
      "created_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### POST `/api/referrals/generate`

**Response `201`:** `{ "success": true, "data": { ...referral }, "message": "Referral code generated." }`

---

### POST `/api/referrals/redeem`

**Request:**
```json
{ "code": "REF-ABC123" }
```

**Response `200`:** `{ "success": true, "data": { ...referral }, "message": "Referral code applied successfully!" }`

---

## Reward Points

### GET `/api/rewards/balance`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "points": 250,
    "value": 2.50
  }
}
```

---

### GET `/api/rewards/history`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "type": "earned",
      "points": 50,
      "description": "Order #BRN-ORD-001",
      "created_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

### POST `/api/rewards/redeem`

**Request:**
```json
{ "amount": 10.00 }
```

**Response `200`:**
```json
{
  "success": true,
  "data": { "points_needed": 1000 }
}
```

---

### GET `/api/rewards/settings`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "points_per_euro": 10,
    "min_redemption_points": 100,
    "point_value": 0.01
  }
}
```

---

## Customer Wallet

### GET `/api/wallet`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "id": 1,
    "balance": 25.50,
    "currency": "EUR",
    "session_id": "..."
  }
}
```

---

### GET `/api/wallet/balance`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "balance": 25.50,
    "currency": "EUR"
  }
}
```

---

### GET `/api/wallet/history`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "type": "credit",
      "amount": 10.00,
      "description": "Refund for order #1",
      "created_at": "2026-05-24T10:00:00.000000Z"
    }
  ]
}
```

---

## VIP Membership

### GET `/api/vip/status`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "id": 1,
    "session_id": "...",
    "tier": "silver",
    "points_required": 500,
    "total_spent": 250.00,
    "orders_count": 5,
    "benefits": ["Free delivery", "10% discount"],
    "started_at": "2026-01-01T00:00:00.000000Z",
    "expires_at": "2027-01-01T00:00:00.000000Z"
  }
}
```

If no membership: `{ "success": true, "data": null, "message": "No VIP membership found for this session." }`

---

### POST `/api/vip/upgrade`

**Request:**
```json
{ "tier": "gold" }
```

**Valid tiers:** `bronze` | `silver` | `gold` | `platinum`

**Response `200`:** `{ "success": true, "data": { ...membership }, "message": "VIP membership upgraded successfully." }`

---

## Member Pricing

### GET `/api/member-prices`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "product_id": 1,
      "tier": "vip",
      "price": 2.49,
      "product": { ... },
      "created_at": "...",
      "updated_at": "..."
    }
  ]
}
```

---

### GET `/api/member-prices/product/{productId}`

**Response `200`:** Prices for a specific product across tiers.

---

### POST `/api/member-prices`

**Request:**
```json
{
  "product_id": 1,
  "tier": "vip",
  "price": 2.49
}
```

**Valid tiers:** `guest` | `registered` | `vip`

---

## Promotions & Deals

### GET `/api/order-value-promotions`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "min_order_value": 50.00,
      "discount_percent": 10,
      "is_active": true
    }
  ]
}
```

---

### GET `/api/quantity-promotions`

**Query (optional):** `product_id=1`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "product_id": 1,
      "type": "buy_x_get_y",
      "buy_qty": 2,
      "get_qty": 1,
      "bundle_price": null,
      "discount_percent": null,
      "is_active": true,
      "product": { ... }
    }
  ]
}
```

---

### GET `/api/daily-deals`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "product_id": 1,
      "discount_percent": 20,
      "deal_price": 2.39,
      "starts_at": "2026-05-24T00:00:00.000000Z",
      "ends_at": "2026-05-24T23:59:59.000000Z",
      "is_active": true,
      "product": { ... }
    }
  ]
}
```

---

### GET `/api/daily-deals/product/{productId}`

**Response `200`:** Single deal, or `404` if none active.

---

### GET `/api/weekly-specials`

**Response `200`:**
```json
{
  "data": [ ...products marked as weekly specials ]
}
```

---

### GET `/api/save-the-food`

**Response `200`:**
```json
{
  "hero": {
    "tag": "Save The Food",
    "title": "Rescue Fresh Food",
    "subtitle": "Up to 50% off"
  },
  "stats": {
    "meals_saved": 1250,
    "co2_saved_kg": 500
  },
  "products": [ ...save-the-food products ]
}
```

---

## Multi-Currency

### GET `/api/currencies`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "code": "EUR",
      "name": "Euro",
      "symbol": "€",
      "rate": 1.0,
      "is_default": true,
      "is_active": true
    }
  ]
}
```

---

### POST `/api/currencies/switch`

**Request:**
```json
{ "code": "USD" }
```

**Response `200`:**
```json
{
  "success": true,
  "data": { ...currency },
  "message": "Switched to USD."
}
```

---

### POST `/api/currencies/convert`

**Request:**
```json
{
  "amount": 100,
  "from": "EUR",
  "to": "USD"
}
```

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "original_amount": 100,
    "converted_amount": 108.5,
    "from": "EUR",
    "to": "USD"
  }
}
```

---

## Language & Translations

### GET `/api/languages`

**Response `200`:**
```json
{
  "success": true,
  "data": [
    {
      "id": 1,
      "code": "de",
      "name": "Deutsch",
      "native_name": "Deutsch",
      "is_default": true,
      "is_active": true
    }
  ]
}
```

---

### GET `/api/languages/{code}`

Example: `/api/languages/de`

**Response `200`:** `{ "success": true, "data": { ...language } }`

---

### POST `/api/languages/switch`

**Request:**
```json
{ "locale": "de" }
```

**Response `200`:**
```json
{
  "success": true,
  "message": "Language switched to Deutsch",
  "data": {
    "locale": "de",
    "language": { ... },
    "translations": {
      "nav.home": "Startseite",
      "nav.products": "Produkte"
    }
  }
}
```

---

### GET `/api/translations/{locale}`

Example: `/api/translations/de`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "locale": "de",
    "translations": {
      "nav.home": "Startseite",
      "nav.products": "Produkte"
    }
  }
}
```

---

## SEO

### GET `/api/seo/products/{slug}`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "meta_title": "Organic Bananas | BERNIE Store",
    "meta_description": "Fresh organic bananas...",
    "canonical_url": "http://localhost:8000/products/organic-bananas",
    "og_title": "Organic Bananas",
    "og_description": "Fresh organic bananas...",
    "og_image": "http://localhost:8000/storage/...",
    "schema_markup": null
  }
}
```

---

### GET `/api/seo/categories/{slug}`

Same response shape as product SEO.

---

## Product Sharing

### GET `/api/products/{slug}/share`

**Response `200`:**
```json
{
  "success": true,
  "data": {
    "url": "http://localhost:8000/products/organic-bananas",
    "facebook": "https://www.facebook.com/sharer/sharer.php?u=...",
    "twitter": "https://twitter.com/intent/tweet?url=...",
    "whatsapp": "https://wa.me/?text=...",
    "telegram": "https://t.me/share/url?url=...",
    "copy_link": "http://localhost:8000/products/organic-bananas",
    "og": {
      "title": "Organic Bananas",
      "description": "Fresh organic bananas.",
      "image": "http://localhost:8000/storage/...",
      "url": "http://localhost:8000/products/organic-bananas"
    }
  }
}
```

---

## Special Pages

See [Promotions & Deals](#promotions--deals) for:
- `GET /api/save-the-food`
- `GET /api/weekly-specials`

---

## Frontend Integration Guide

### 1. Session cookies (required for cart/checkout)

All cart, basket, order, wishlist, wallet, rewards, and referral endpoints use **session cookies**. Always send credentials:

```javascript
// Fetch
fetch("http://localhost:8000/api/cart", {
  credentials: "include",
});

// Axios
axios.defaults.withCredentials = true;
```

The first request to any session endpoint automatically creates a session.

---

### 2. Customer authentication (optional)

For logged-in customers (profile, linked orders):

```javascript
// Login
const res = await fetch("http://localhost:8000/api/auth/login", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({ email, password }),
});
const { data } = await res.json();
const token = data.token;

// Use token on protected routes
fetch("http://localhost:8000/api/auth/me", {
  headers: { Authorization: `Bearer ${token}` },
});
```

Store the token in localStorage or a secure cookie on the frontend.

---

### 3. CSRF (if needed)

For session-based POST/PUT/DELETE, call once before mutations:

```javascript
await fetch("http://localhost:8000/sanctum/csrf-cookie", {
  credentials: "include",
});
```

Auth routes (`/api/auth/*`) are CSRF-exempt.

---

### 4. Response envelopes

Most endpoints wrap data in one of these shapes:

```json
{ "data": ... }                          // Laravel JsonResource
{ "success": true, "data": ... }         // Custom controllers
{ "success": true, "message": "..." }    // Action confirmations
```

Always check `success` and HTTP status codes for errors.

---

### 5. Image upload

**Option A — Upload with product/category (multipart):**

```javascript
const formData = new FormData();
formData.append("name", "Organic Apples");
formData.append("slug", "organic-apples");
formData.append("price", "3.99");
formData.append("image", fileInput.files[0]);

await fetch("http://localhost:8000/api/products", {
  method: "POST",
  credentials: "include",
  body: formData,
});
```

**Option B — Upload via media endpoint first:**

```javascript
const mediaForm = new FormData();
mediaForm.append("file", file);
const { url } = await fetch("/api/media", { method: "POST", body: mediaForm }).then(r => r.json());
```

Supported formats: jpg, jpeg, png, gif, webp, svg — max 2MB.

---

### 6. Typical checkout flow

```
1. GET  /api/cart                    → show cart
2. POST /api/delivery/check          → validate postal code
3. POST /api/checkout/preview        → calculate totals (coupon, points, wallet)
4. POST /api/orders                  → create order
5. POST /api/orders/{id}/pay         → process payment
6. GET  /api/orders/{id}             → show confirmation
```

---

### 7. Error handling

| Status | Meaning |
|--------|---------|
| `200` | Success |
| `201` | Created |
| `204` | Success, no body |
| `401` | Unauthorized (missing/invalid token) |
| `403` | Forbidden (deactivated account) |
| `404` | Not found |
| `422` | Validation error or business rule failure |
| `500` | Server error |

Validation errors (`422`):
```json
{
  "message": "The given data was invalid.",
  "errors": {
    "email": ["The email field is required."]
  }
}
```

---

### 8. Environment

| Variable | Default | Description |
|----------|---------|-------------|
| Base URL | `http://localhost:8000/api` | Change for production |
| CORS | Configure in Laravel | Allow frontend origin + credentials |

---

**Total endpoints documented:** 100  
**Last updated:** July 2026
