# API Endpoints Reference

**Document Version:** 1.0
**Last Updated:** 2026-01-10
**Application:** Norda Biznes Hub
**Base URL:** https://nordabiznes.pl

---

## Table of Contents

1. [Overview](#overview)
2. [Authentication](#authentication)
3. [Rate Limiting](#rate-limiting)
4. [CSRF Protection](#csrf-protection)
5. [Response Formats](#response-formats)
6. [Public Endpoints](#public-endpoints)
7. [Authentication Endpoints](#authentication-endpoints)
8. [User Endpoints](#user-endpoints)
9. [API Endpoints (JSON)](#api-endpoints-json)
10. [Admin Endpoints](#admin-endpoints)
11. [Audit Endpoints](#audit-endpoints)
12. [Error Codes](#error-codes)
13. [Examples](#examples)

---

## Overview

The Norda Biznes Hub provides **90+ HTTP endpoints** across multiple functional areas:

- **Public Pages:** Company directory, search, profile viewing
- **Authentication:** Registration, login, password reset, email verification
- **User Features:** Dashboard, AI chat, forum, messaging, calendar, classifieds
- **API (JSON):** RESTful endpoints for programmatic access
- **Admin:** Content moderation, user management, audit tools, analytics
- **Audit:** Public audit reports (SEO, Social Media, GBP, IT)

### Technology Stack

- **Framework:** Flask 3.0
- **WSGI Server:** Gunicorn (4 workers, 120s timeout)
- **Session Management:** Flask-Login (server-side sessions)
- **CSRF Protection:** Flask-WTF CSRFProtect
- **Rate Limiting:** Flask-Limiter (IP-based)

### URL Structure

```
https://nordabiznes.pl/
├── /                          # Public pages
├── /api/                      # JSON API endpoints
├── /admin/                    # Admin-only pages
├── /audit/                    # Public audit reports
└── /company/<slug>            # Company profiles
```

---

## Authentication

### Authentication Methods

1. **Session-based (Browser):**
   - Flask-Login sessions
   - Cookie: `session` (HttpOnly, Secure, SameSite=Lax)
   - Duration: 7 days with "Remember Me" checkbox
   - Logout: `GET /logout`

2. **No API Key Authentication:**
   - Public API endpoints require no authentication
   - Protected endpoints require active browser session

### Authorization Levels

| Level | Description | Check Method |
|-------|-------------|--------------|
| **Public** | No authentication required | None |
| **Authenticated** | Logged-in user | `@login_required` decorator |
| **NORDA Member** | User with verified company association | `current_user.is_verified` |
| **Admin** | Admin privileges | `current_user.is_admin == True` |

### Access Control Pattern

```python
# Public endpoint (no decorator)
@app.route('/search')
def search():
    # Anyone can access

# Authenticated endpoint
@app.route('/dashboard')
@login_required
def dashboard():
    # Requires login

# Admin endpoint
@app.route('/admin/users')
@login_required
def admin_users():
    if not current_user.is_admin:
        flash('Brak uprawnień administratora', 'danger')
        return redirect(url_for('index'))
    # Admin logic
```

---

## Rate Limiting

### Global Rate Limits

Configured via Flask-Limiter, applied by IP address:

- **200 requests per day**
- **50 requests per hour**

### Per-Endpoint Limits

Some endpoints have additional rate limiting:

| Endpoint | Limit | Reason |
|----------|-------|--------|
| `POST /login` | 5 requests/hour | Brute force protection |
| `POST /register` | 5 requests/hour | Abuse prevention |
| `POST /forgot-password` | 5 requests/hour | Email spam prevention |
| `POST /api/seo/audit` | 10 requests/hour | API quota protection |
| `POST /api/chat/*/message` | 50 requests/hour | AI API cost control |

### Rate Limit Headers

Responses include rate limit information:

```http
X-RateLimit-Limit: 50
X-RateLimit-Remaining: 47
X-RateLimit-Reset: 1704974400
```

### Rate Limit Exceeded Response

```http
HTTP/1.1 429 Too Many Requests
Content-Type: application/json

{
  "error": "Rate limit exceeded",
  "retry_after": 3600
}
```

---

## CSRF Protection

### Overview

All **POST, PUT, DELETE** requests require CSRF token validation (Flask-WTF CSRFProtect).

### CSRF Token in Forms

HTML forms automatically include CSRF token:

```html
<form method="POST" action="/forum/nowy">
  {{ form.hidden_tag() }}  <!-- Includes CSRF token -->
  <!-- Form fields -->
</form>
```

### CSRF Token in AJAX

For AJAX requests, include CSRF token in headers:

```javascript
fetch('/api/chat/start', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-CSRFToken': getCsrfToken()  // Get from meta tag or cookie
  },
  body: JSON.stringify({...})
});
```

### CSRF Token Retrieval

Token available in HTML meta tag:

```html
<meta name="csrf-token" content="{{ csrf_token() }}">
```

JavaScript helper:

```javascript
function getCsrfToken() {
  return document.querySelector('meta[name="csrf-token"]').content;
}
```

### CSRF Exemptions

No endpoints are exempt from CSRF protection.

---

## Response Formats

### HTML Responses

Server-side rendered Jinja2 templates:

```http
GET /company/pixlab-sp-z-o-o
→ HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8

<!DOCTYPE html>
<html>...
```

### JSON Responses

API endpoints return JSON:

```http
GET /api/companies
→ HTTP/1.1 200 OK
Content-Type: application/json

{
  "companies": [...],
  "total": 80
}
```

### Flash Messages

User-facing messages use Flask flash messages:

```python
flash('Rekomendacja dodana pomyślnie', 'success')
flash('Błąd: Nieprawidłowe dane', 'danger')
```

Categories: `success`, `danger`, `warning`, `info`

### Redirects

Many POST endpoints redirect after success:

```http
POST /login
→ HTTP/1.1 302 Found
Location: /dashboard
```

---

## Public Endpoints

### Homepage

```http
GET /
```

**Description:** Company directory homepage with grid of all companies

**Authentication:** None

**Query Parameters:**
- None

**Response:**
- HTML page with company cards
- Displays all 80 member companies
- Filterable by category (client-side)

**Example:**
```bash
curl https://nordabiznes.pl/
```

---

### Company Search

```http
GET /search
```

**Description:** Search companies by keyword, NIP, REGON, or category

**Authentication:** None

**Query Parameters:**

| Parameter | Type | Required | Description | Example |
|-----------|------|----------|-------------|---------|
| `q` | string | No | Search query (keyword, NIP, REGON) | `strony www` |
| `category` | integer | No | Category ID filter | `1` (IT) |

**Search Strategies:**

1. **NIP/REGON Direct Lookup** (10 digits → NIP, 9/14 digits → REGON)
2. **Synonym Expansion** (55+ keyword mappings)
3. **PostgreSQL FTS** (full-text search with Polish stemming)
4. **Fuzzy Matching** (pg_trgm for typos)

**Response:**
- HTML page with search results
- Results sorted by relevance score
- Empty state if no matches

**Example:**
```bash
curl "https://nordabiznes.pl/search?q=strony+www&category=1"
```

---

### Company Profile

```http
GET /company/<slug>
```

**Description:** Detailed company profile page

**Authentication:** None

**Path Parameters:**

| Parameter | Type | Description | Example |
|-----------|------|-------------|---------|
| `slug` | string | Company URL slug (kebab-case) | `pixlab-sp-z-o-o` |

**Response Sections:**

1. Header (name, category, verification badge, short description)
2. Contact bar (website, email, phone, location)
3. About (company description)
4. Services & Competencies (tags)
5. Unique Selling Points
6. Contact Details (full contact cards)
7. Legal & Business Info (NIP, REGON, KRS, year established)
8. Social Media (6 platforms)
9. Website Analysis (SEO, performance scores)

**Example:**
```bash
curl https://nordabiznes.pl/company/pixlab-sp-z-o-o
```

**404 Response:**
```http
HTTP/1.1 404 Not Found
Content-Type: text/html

<h1>Firma nie została znaleziona</h1>
```

---

### Health Check

```http
GET /health
```

**Description:** System health check endpoint for monitoring

**Authentication:** None

**Response:**

```json
{
  "status": "ok",
  "database": "connected",
  "timestamp": "2026-01-10T12:00:00Z"
}
```

**Status Codes:**
- `200 OK` - System healthy
- `500 Internal Server Error` - Database connection failed

**Example:**
```bash
curl https://nordabiznes.pl/health
```

**Use Case:** Zabbix monitoring, uptime checks

---

### Company Events/News

```http
GET /aktualnosci
```

**Description:** Public feed of company events and news

**Authentication:** None

**Response:**
- HTML page with list of recent company events
- Sorted by date (newest first)
- Pagination (20 events per page)

**Example:**
```bash
curl https://nordabiznes.pl/aktualnosci
```

---

### Release Notes

```http
GET /release-notes
```

**Description:** Application changelog and version history

**Authentication:** None

**Response:**
- HTML page with release notes
- Grouped by version
- Change history from `app.py`

**Example:**
```bash
curl https://nordabiznes.pl/release-notes
```

---

## Authentication Endpoints

### User Registration

```http
POST /register
```

**Description:** Create new user account with email verification

**Authentication:** None

**Rate Limit:** 5 requests/hour

**Request Body (Form):**

| Field | Type | Required | Validation | Description |
|-------|------|----------|------------|-------------|
| `email` | string | Yes | Email format, unique | User email address |
| `password` | string | Yes | 8+ chars, uppercase, lowercase, digit | Account password |
| `first_name` | string | Yes | 1-100 chars | User first name |
| `last_name` | string | Yes | 1-100 chars | User last name |
| `company_id` | integer | No | Valid company ID | Associated company (optional) |

**Password Requirements:**
- Minimum 8 characters
- At least one uppercase letter
- At least one lowercase letter
- At least one digit

**Workflow:**

```
1. Validate input
2. Check email uniqueness
3. Hash password (PBKDF2:SHA256)
4. Create User (is_verified=False)
5. Generate verification token (32-byte URL-safe)
6. Send verification email (Microsoft Graph API)
7. Redirect to /login with flash message
```

**Success Response:**
```http
HTTP/1.1 302 Found
Location: /login
Set-Cookie: session=...

Flash: "Konto utworzone. Sprawdź email w celu weryfikacji."
```

**Error Response:**
```http
HTTP/1.1 200 OK
Content-Type: text/html

Flash: "Email już istnieje w systemie"
```

**Example:**
```bash
curl -X POST https://nordabiznes.pl/register \
  -d "email=jan.kowalski@example.com" \
  -d "password=SecurePass123" \
  -d "first_name=Jan" \
  -d "last_name=Kowalski"
```

---

### Email Verification

```http
GET /verify-email/<token>
```

**Description:** Verify user email address via token from email

**Authentication:** None

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `token` | string | Verification token (32-byte URL-safe) |

**Token Properties:**
- Length: 43 characters (base64-encoded 32 bytes)
- Storage: `users.verification_token`
- Expiry: No expiration (should be implemented)

**Workflow:**

```
1. Query User by verification_token
2. If found: Set is_verified=True, verification_token=NULL
3. If not found: Show error
4. Redirect to /login
```

**Success Response:**
```http
HTTP/1.1 302 Found
Location: /login

Flash: "Email zweryfikowany pomyślnie!"
```

**Error Response:**
```http
HTTP/1.1 302 Found
Location: /login

Flash: "Nieprawidłowy lub wygasły token weryfikacyjny"
```

**Example:**
```bash
curl https://nordabiznes.pl/verify-email/AbCdEf123456...
```

---

### User Login

```http
POST /login
```

**Description:** Authenticate user and create session

**Authentication:** None

**Rate Limit:** 5 requests/hour

**Request Body (Form):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | User email |
| `password` | string | Yes | User password |
| `remember` | boolean | No | Remember me (7 day session) |

**Workflow:**

```
1. Query User by email
2. Verify password (werkzeug.security.check_password_hash)
3. Check is_verified = True
4. Check is_active = True
5. Call login_user(user, remember=True/False)
6. Redirect to /dashboard or ?next URL
```

**Success Response:**
```http
HTTP/1.1 302 Found
Location: /dashboard
Set-Cookie: session=...; HttpOnly; Secure; SameSite=Lax
```

**Error Response:**
```http
HTTP/1.1 200 OK
Content-Type: text/html

Flash: "Nieprawidłowy email lub hasło"
```

**Example:**
```bash
curl -X POST https://nordabiznes.pl/login \
  -d "email=jan.kowalski@example.com" \
  -d "password=SecurePass123" \
  -d "remember=on"
```

---

### User Logout

```http
GET /logout
```

**Description:** End user session

**Authentication:** Required

**Response:**
```http
HTTP/1.1 302 Found
Location: /
Set-Cookie: session=; Expires=...

Flash: "Wylogowano pomyślnie"
```

**Example:**
```bash
curl https://nordabiznes.pl/logout \
  -H "Cookie: session=..."
```

---

### Password Reset Request

```http
POST /forgot-password
```

**Description:** Request password reset email

**Authentication:** None

**Rate Limit:** 5 requests/hour

**Request Body (Form):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `email` | string | Yes | User email address |

**Workflow:**

```
1. Query User by email
2. Generate reset_token (32-byte URL-safe)
3. Save to users.reset_token
4. Send reset email with link to /reset-password/<token>
5. Redirect to /login with flash message
```

**Response:**
```http
HTTP/1.1 302 Found
Location: /login

Flash: "Email z linkiem do resetowania hasła został wysłany"
```

**Note:** Returns success message even if email not found (security best practice)

---

### Password Reset

```http
POST /reset-password/<token>
```

**Description:** Reset password using token from email

**Authentication:** None

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `token` | string | Reset token (32-byte URL-safe) |

**Request Body (Form):**

| Field | Type | Required | Validation |
|-------|------|----------|------------|
| `password` | string | Yes | 8+ chars, uppercase, lowercase, digit |
| `password_confirm` | string | Yes | Must match password |

**Workflow:**

```
1. Query User by reset_token
2. Validate token exists
3. Validate password strength
4. Hash new password
5. Update user.password_hash
6. Clear reset_token
7. Redirect to /login
```

**Success Response:**
```http
HTTP/1.1 302 Found
Location: /login

Flash: "Hasło zmienione pomyślnie"
```

**Error Response:**
```http
HTTP/1.1 200 OK

Flash: "Nieprawidłowy lub wygasły token resetowania"
```

---

## User Endpoints

### User Dashboard

```http
GET /dashboard
```

**Description:** Personalized user dashboard

**Authentication:** Required

**Features:**
- User profile summary
- Recent activity
- Quick actions (AI chat, forum, messages)
- Company profile link (if associated)

**Response:**
- HTML page with dashboard

**Example:**
```bash
curl https://nordabiznes.pl/dashboard \
  -H "Cookie: session=..."
```

---

### AI Chat Interface

```http
GET /chat
```

**Description:** AI-powered company directory assistant

**Authentication:** Required

**Features:**
- Start new conversation
- View conversation history
- Interactive chat interface
- Cost tracking display

**Response:**
- HTML page with chat UI

**Example:**
```bash
curl https://nordabiznes.pl/chat \
  -H "Cookie: session=..."
```

---

### Forum - Topic List

```http
GET /forum
```

**Description:** Community forum topic listing

**Authentication:** Required

**Query Parameters:**

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `page` | integer | Page number | 1 |

**Response:**
- HTML page with forum topics
- Pagination (20 topics per page)
- Pinned topics at top
- Topic metadata (author, replies, last post)

---

### Forum - Create Topic

```http
POST /forum/nowy
```

**Description:** Create new forum topic

**Authentication:** Required

**Request Body (Form):**

| Field | Type | Required | Max Length | Description |
|-------|------|----------|------------|-------------|
| `title` | string | Yes | 200 chars | Topic title |
| `content` | string | Yes | 10,000 chars | Topic content (sanitized HTML) |

**Input Sanitization:**
- Strips dangerous HTML tags
- Allows basic formatting (b, i, u, br, p)
- Max length enforcement

**Success Response:**
```http
HTTP/1.1 302 Found
Location: /forum/<topic_id>

Flash: "Temat utworzony pomyślnie"
```

---

### Forum - View Topic

```http
GET /forum/<topic_id>
```

**Description:** View forum topic with replies

**Authentication:** Required

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `topic_id` | integer | Forum topic ID |

**Response:**
- Topic details (title, content, author, timestamp)
- All replies (nested threading)
- Reply form

---

### Forum - Reply to Topic

```http
POST /forum/<topic_id>/odpowiedz
```

**Description:** Add reply to forum topic

**Authentication:** Required

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `topic_id` | integer | Forum topic ID |

**Request Body (Form):**

| Field | Type | Required | Max Length |
|-------|------|----------|------------|
| `content` | string | Yes | 10,000 chars |

**Error Handling:**
- 404 if topic not found
- 403 if topic is locked
- Input sanitization applied

**Success Response:**
```http
HTTP/1.1 302 Found
Location: /forum/<topic_id>

Flash: "Odpowiedź dodana"
```

---

### Calendar - Event List

```http
GET /kalendarz
```

**Description:** Association event calendar

**Authentication:** Required

**Response:**
- HTML page with upcoming events
- Event details (date, time, location, description)
- RSVP status for current user

---

### Calendar - RSVP

```http
POST /kalendarz/<event_id>/rsvp
```

**Description:** RSVP to event (attend/cancel)

**Authentication:** Required

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `event_id` | integer | Event ID |

**Request Body (Form):**

| Field | Type | Values | Description |
|-------|------|--------|-------------|
| `status` | string | `attending`, `not_attending` | RSVP status |

**Workflow:**

```
1. Check if EventAttendee exists for user+event
2. If exists: Update status
3. If not: Create EventAttendee record
4. Redirect to /kalendarz/<event_id>
```

**Response:**
```http
HTTP/1.1 302 Found
Location: /kalendarz/<event_id>

Flash: "RSVP zaktualizowane"
```

---

### Messages - Inbox

```http
GET /wiadomosci
```

**Description:** Private message inbox

**Authentication:** Required

**Response:**
- HTML page with received messages
- Unread count badge
- Message preview (sender, subject, timestamp)
- Pagination (20 messages per page)

---

### Messages - Sent

```http
GET /wiadomosci/wyslane
```

**Description:** Sent messages folder

**Authentication:** Required

**Response:**
- HTML page with sent messages
- Recipient, subject, timestamp
- Pagination (20 messages per page)

---

### Messages - New Message

```http
GET /wiadomosci/nowa
```

**Description:** Compose new message form

**Authentication:** Required

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `recipient` | integer | User ID to pre-fill recipient |
| `reply_to` | integer | Message ID to reply to |

**Response:**
- HTML form with recipient selector, subject, content

---

### Messages - Send

```http
POST /wiadomosci/wyslij
```

**Description:** Send private message to another user

**Authentication:** Required

**Request Body (Form):**

| Field | Type | Required | Max Length |
|-------|------|----------|------------|
| `recipient_id` | integer | Yes | - |
| `subject` | string | Yes | 200 chars |
| `content` | string | Yes | 10,000 chars |

**Validation:**
- Recipient must exist and be active
- Cannot send to self
- Content sanitization

**Success Response:**
```http
HTTP/1.1 302 Found
Location: /wiadomosci/wyslane

Flash: "Wiadomość wysłana"
```

---

### Messages - View

```http
GET /wiadomosci/<message_id>
```

**Description:** View message details

**Authentication:** Required

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `message_id` | integer | Message ID |

**Authorization:**
- User must be sender or recipient
- Returns 403 otherwise

**Side Effects:**
- Marks message as read (if current user is recipient)

**Response:**
- HTML page with full message content
- Reply button

---

### Classifieds - List

```http
GET /tablica
```

**Description:** Community classifieds board

**Authentication:** Required

**Response:**
- HTML page with active classifieds
- Filter by status (active, completed)
- Pagination (20 classifieds per page)

---

### Classifieds - Post New

```http
POST /tablica/nowe
```

**Description:** Post new classified ad

**Authentication:** Required

**Request Body (Form):**

| Field | Type | Required | Max Length |
|-------|------|----------|------------|
| `title` | string | Yes | 200 chars |
| `description` | string | Yes | 10,000 chars |
| `price` | decimal | No | - |
| `category` | string | Yes | Enum |

**Categories:** `offer`, `request`, `event`, `other`

**Success Response:**
```http
HTTP/1.1 302 Found
Location: /tablica/<classified_id>

Flash: "Ogłoszenie dodane"
```

---

### Classifieds - Mark Completed

```http
POST /tablica/<classified_id>/zakoncz
```

**Description:** Mark classified as completed/closed

**Authentication:** Required (must be author)

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `classified_id` | integer | Classified ID |

**Authorization:**
- Only author can mark as completed

**Response:**
```http
HTTP/1.1 302 Found
Location: /tablica/<classified_id>

Flash: "Ogłoszenie zakończone"
```

---

## API Endpoints (JSON)

### Companies List (JSON Export)

```http
GET /api/companies
```

**Description:** Export all companies as JSON

**Authentication:** None (public API)

**Query Parameters:**

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `category` | integer | Filter by category ID | All |
| `limit` | integer | Max companies to return | 100 |

**Response:**

```json
{
  "companies": [
    {
      "id": 26,
      "name": "PIXLAB Sp. z o.o.",
      "slug": "pixlab-sp-z-o-o",
      "short_description": "Systemy informatyczne dla biznesu",
      "category": "IT",
      "nip": "5882436505",
      "regon": "221912907",
      "krs": "0000414920",
      "website_url": "https://pixlab.pl",
      "email": "kontakt@pixlab.pl",
      "phone": "58 621 30 00",
      "city": "Rumia",
      "services": ["Oprogramowanie", "Systemy IT", "Hosting"],
      "competencies": ["Python", "PostgreSQL", "DevOps"],
      "founded_year": 2011
    },
    // ... more companies
  ],
  "total": 80,
  "category": null,
  "timestamp": "2026-01-10T12:00:00Z"
}
```

**Status Codes:**
- `200 OK` - Success
- `400 Bad Request` - Invalid parameters

**Example:**
```bash
curl https://nordabiznes.pl/api/companies
curl "https://nordabiznes.pl/api/companies?category=1&limit=10"
```

---

### Chat - Start Conversation

```http
POST /api/chat/start
```

**Description:** Initialize new AI chat conversation

**Authentication:** Required

**Request Body:**

```json
{
  "initial_message": "Szukam firm z obszaru IT"
}
```

**Response:**

```json
{
  "conversation_id": 123,
  "created_at": "2026-01-10T12:00:00Z",
  "message": "Witaj! W czym mogę pomóc?"
}
```

**Status Codes:**
- `201 Created` - Conversation started
- `401 Unauthorized` - Not logged in
- `429 Too Many Requests` - Rate limit exceeded

**Example:**
```bash
curl -X POST https://nordabiznes.pl/api/chat/start \
  -H "Cookie: session=..." \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: ..." \
  -d '{"initial_message": "Szukam firm IT"}'
```

---

### Chat - Send Message

```http
POST /api/chat/<conversation_id>/message
```

**Description:** Send message to AI chat

**Authentication:** Required

**Rate Limit:** 50 requests/hour

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `conversation_id` | integer | Conversation ID |

**Request Body:**

```json
{
  "message": "Kto tworzy strony www?"
}
```

**Response:**

```json
{
  "response": "Znalazłem 5 firm zajmujących się tworzeniem stron www:\n\n1. **PIXLAB** - strony internetowe, sklepy online...",
  "companies_found": 5,
  "tokens_used": 12500,
  "estimated_cost_usd": 0.00094,
  "timestamp": "2026-01-10T12:00:05Z"
}
```

**AI Chat Configuration:**
- Model: gemini-2.5-flash
- Max companies in context: 8
- History: Last 10 messages
- Average latency: 250-350ms
- Cost tracking: Automatic

**Status Codes:**
- `200 OK` - Success
- `400 Bad Request` - Empty message
- `401 Unauthorized` - Not logged in
- `404 Not Found` - Conversation not found
- `429 Too Many Requests` - Rate limit
- `500 Internal Server Error` - AI API error

**Example:**
```bash
curl -X POST https://nordabiznes.pl/api/chat/123/message \
  -H "Cookie: session=..." \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: ..." \
  -d '{"message": "Kto tworzy strony www?"}'
```

---

### Chat - Get History

```http
GET /api/chat/<conversation_id>/history
```

**Description:** Retrieve conversation history

**Authentication:** Required

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `conversation_id` | integer | Conversation ID |

**Response:**

```json
{
  "conversation_id": 123,
  "created_at": "2026-01-10T12:00:00Z",
  "messages": [
    {
      "id": 1,
      "sender": "user",
      "message": "Szukam firm IT",
      "timestamp": "2026-01-10T12:00:00Z"
    },
    {
      "id": 2,
      "sender": "ai",
      "message": "Znalazłem 12 firm IT...",
      "timestamp": "2026-01-10T12:00:02Z",
      "tokens_used": 8500,
      "cost_usd": 0.00064
    }
  ],
  "total_messages": 2,
  "total_cost_usd": 0.00064
}
```

**Example:**
```bash
curl https://nordabiznes.pl/api/chat/123/history \
  -H "Cookie: session=..."
```

---

### Chat - Submit Feedback

```http
POST /api/chat/feedback
```

**Description:** Submit feedback on AI response

**Authentication:** Required

**Request Body:**

```json
{
  "message_id": 456,
  "thumbs_up": true,
  "thumbs_down": false,
  "comment": "Bardzo pomocna odpowiedź!"
}
```

**Response:**

```json
{
  "status": "success",
  "message": "Dziękujemy za feedback"
}
```

---

### Verify NIP

```http
GET /api/verify-nip
```

**Description:** Verify Polish NIP (tax identification number) via ALEO.com

**Authentication:** None

**Query Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `nip` | string | Yes | 10-digit NIP (no hyphens) |

**Response:**

```json
{
  "valid": true,
  "nip": "5882436505",
  "company_name": "PIXLAB SPÓŁKA Z OGRANICZONĄ ODPOWIEDZIALNOŚCIĄ",
  "status": "active",
  "source": "aleo.com"
}
```

**Invalid NIP:**

```json
{
  "valid": false,
  "nip": "1234567890",
  "error": "NIP nie został znaleziony"
}
```

**Example:**
```bash
curl "https://nordabiznes.pl/api/verify-nip?nip=5882436505"
```

---

### Check Email Availability

```http
GET /api/check-email
```

**Description:** Check if email is available for registration

**Authentication:** None

**Query Parameters:**

| Parameter | Type | Required | Description |
|-----------|------|----------|-------------|
| `email` | string | Yes | Email address to check |

**Response:**

```json
{
  "available": true,
  "email": "jan.kowalski@example.com"
}
```

**Email Taken:**

```json
{
  "available": false,
  "email": "existing@example.com"
}
```

**Example:**
```bash
curl "https://nordabiznes.pl/api/check-email?email=jan.kowalski@example.com"
```

---

### Notifications - List

```http
GET /api/notifications
```

**Description:** Get user notifications

**Authentication:** Required

**Query Parameters:**

| Parameter | Type | Description | Default |
|-----------|------|-------------|---------|
| `unread_only` | boolean | Filter unread notifications | false |
| `limit` | integer | Max notifications to return | 20 |

**Response:**

```json
{
  "notifications": [
    {
      "id": 1,
      "type": "new_message",
      "message": "Nowa wiadomość od Jan Kowalski",
      "url": "/wiadomosci/123",
      "created_at": "2026-01-10T11:00:00Z",
      "read": false
    },
    {
      "id": 2,
      "type": "new_recommendation",
      "message": "Nowa rekomendacja dla Twojej firmy",
      "url": "/admin/recommendations",
      "created_at": "2026-01-09T15:30:00Z",
      "read": true
    }
  ],
  "unread_count": 3,
  "total": 15
}
```

**Notification Types:**
- `new_message` - New private message
- `new_recommendation` - New recommendation received
- `event_reminder` - Upcoming event reminder
- `news_approved` - Company news approved (future)
- `news_rejected` - Company news rejected (future)

**Example:**
```bash
curl "https://nordabiznes.pl/api/notifications?unread_only=true" \
  -H "Cookie: session=..."
```

---

### Notifications - Mark Read

```http
POST /api/notifications/<notification_id>/read
```

**Description:** Mark notification as read

**Authentication:** Required

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `notification_id` | integer | Notification ID |

**Response:**

```json
{
  "status": "success",
  "notification_id": 1,
  "read": true
}
```

**Example:**
```bash
curl -X POST https://nordabiznes.pl/api/notifications/1/read \
  -H "Cookie: session=..." \
  -H "X-CSRFToken: ..."
```

---

### Notifications - Mark All Read

```http
POST /api/notifications/read-all
```

**Description:** Mark all user notifications as read

**Authentication:** Required

**Response:**

```json
{
  "status": "success",
  "marked_read": 5
}
```

**Example:**
```bash
curl -X POST https://nordabiznes.pl/api/notifications/read-all \
  -H "Cookie: session=..." \
  -H "X-CSRFToken: ..."
```

---

### Notifications - Unread Count

```http
GET /api/notifications/unread-count
```

**Description:** Get count of unread notifications (for badge)

**Authentication:** Required

**Response:**

```json
{
  "unread_count": 3
}
```

**Example:**
```bash
curl https://nordabiznes.pl/api/notifications/unread-count \
  -H "Cookie: session=..."
```

---

### Messages - Unread Count

```http
GET /api/messages/unread-count
```

**Description:** Get count of unread private messages

**Authentication:** Required

**Response:**

```json
{
  "unread_count": 2
}
```

**Example:**
```bash
curl https://nordabiznes.pl/api/messages/unread-count \
  -H "Cookie: session=..."
```

---

### Model Info (Gemini)

```http
GET /api/model-info
```

**Description:** Get information about available AI models

**Authentication:** None

**Response:**

```json
{
  "models": [
    {
      "id": "flash",
      "name": "gemini-2.5-flash",
      "description": "Fast, cost-effective model for most tasks",
      "pricing": {
        "input_per_1m_tokens": 0.075,
        "output_per_1m_tokens": 0.30
      },
      "default": true
    },
    {
      "id": "pro",
      "name": "gemini-2.5-pro",
      "description": "High-quality model for complex tasks",
      "pricing": {
        "input_per_1m_tokens": 1.25,
        "output_per_1m_tokens": 5.00
      },
      "default": false
    }
  ]
}
```

---

## Admin Endpoints

### Admin - Users

```http
GET /admin/users
```

**Description:** User management dashboard

**Authentication:** Admin only

**Features:**
- List all users
- Search by email/name
- Toggle admin status
- Toggle active status
- Delete users

**Response:**
- HTML page with user table

---

### Admin - Toggle Admin Status

```http
POST /admin/users/<user_id>/toggle-admin
```

**Description:** Grant/revoke admin privileges

**Authentication:** Admin only

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `user_id` | integer | User ID |

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/users

Flash: "Status administratora zaktualizowany"
```

---

### Admin - Recommendations

```http
GET /admin/recommendations
```

**Description:** Moderation queue for company recommendations

**Authentication:** Admin only

**Query Parameters:**

| Parameter | Type | Values | Default |
|-----------|------|--------|---------|
| `status` | string | `pending`, `approved`, `rejected` | `pending` |

**Features:**
- Filter by status
- Approve/reject with reason
- View recommendation details

**Response:**
- HTML page with recommendations table

---

### Admin - Approve Recommendation

```http
POST /admin/recommendations/<id>/approve
```

**Description:** Approve pending recommendation

**Authentication:** Admin only

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | integer | Recommendation ID |

**Workflow:**

```
1. Update status = 'approved'
2. Set moderated_by = current_user.id
3. Set moderated_at = now()
4. (Future) Send notification to recommender
5. Redirect to /admin/recommendations
```

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/recommendations

Flash: "Rekomendacja zatwierdzona"
```

---

### Admin - Reject Recommendation

```http
POST /admin/recommendations/<id>/reject
```

**Description:** Reject pending recommendation

**Authentication:** Admin only

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | integer | Recommendation ID |

**Request Body (Form):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `rejection_reason` | string | Yes | Reason for rejection |

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/recommendations

Flash: "Rekomendacja odrzucona"
```

---

### Admin - Forum Moderation

```http
GET /admin/forum
```

**Description:** Forum moderation dashboard

**Authentication:** Admin only

**Features:**
- Pin/unpin topics
- Lock/unlock topics
- Delete topics
- Delete replies
- View all topics (including locked)

---

### Admin - Pin Topic

```http
POST /admin/forum/topic/<id>/pin
```

**Description:** Pin topic to top of forum

**Authentication:** Admin only

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/forum

Flash: "Temat przypięty"
```

---

### Admin - Lock Topic

```http
POST /admin/forum/topic/<id>/lock
```

**Description:** Lock topic (prevent new replies)

**Authentication:** Admin only

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/forum

Flash: "Temat zablokowany"
```

---

### Admin - Delete Topic

```http
POST /admin/forum/topic/<id>/delete
```

**Description:** Delete forum topic and all replies

**Authentication:** Admin only

**Warning:** Permanent deletion, cascade deletes all replies

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/forum

Flash: "Temat usunięty"
```

---

### Admin - Delete Reply

```http
POST /admin/forum/reply/<id>/delete
```

**Description:** Delete individual forum reply

**Authentication:** Admin only

**Response:**
```http
HTTP/1.1 302 Found
Location: /forum/<topic_id>

Flash: "Odpowiedź usunięta"
```

---

### Admin - Membership Fees

```http
GET /admin/fees
```

**Description:** Membership fee management dashboard

**Authentication:** Admin only

**Features:**
- View all fees by period
- Filter by status (pending, paid, overdue)
- Generate monthly fees
- Mark fees as paid (single or bulk)
- Export to Excel

---

### Admin - Generate Monthly Fees

```http
POST /admin/fees/generate
```

**Description:** Generate membership fees for all companies for a given month

**Authentication:** Admin only

**Request Body (Form):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `period_start` | date | Yes | Start of period (YYYY-MM-DD) |
| `period_end` | date | Yes | End of period (YYYY-MM-DD) |

**Workflow:**

```
1. Get fee amount from membership_fee_config
2. Query all active companies
3. For each company:
   - Check if fee exists for period
   - If not: Create MembershipFee (status='pending')
4. Redirect to /admin/fees
```

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/fees

Flash: "Wygenerowano składki dla 80 firm"
```

---

### Admin - Mark Fee Paid

```http
POST /admin/fees/<id>/mark-paid
```

**Description:** Mark single fee as paid

**Authentication:** Admin only

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `id` | integer | Fee ID |

**Request Body (Form):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `paid_at` | datetime | No | Payment date (default: now) |
| `payment_method` | string | No | `przelew`, `gotówka`, `other` |

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/fees

Flash: "Składka oznaczona jako opłacona"
```

---

### Admin - Bulk Mark Paid

```http
POST /admin/fees/bulk-mark-paid
```

**Description:** Mark multiple fees as paid

**Authentication:** Admin only

**Request Body (Form):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `fee_ids[]` | array[integer] | Yes | Array of fee IDs |
| `payment_method` | string | No | Payment method |

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/fees

Flash: "Oznaczono 15 składek jako opłacone"
```

---

### Admin - Export Fees

```http
GET /admin/fees/export
```

**Description:** Export fees to Excel file

**Authentication:** Admin only

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `period_start` | date | Filter by period start |
| `period_end` | date | Filter by period end |

**Response:**
```http
HTTP/1.1 200 OK
Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
Content-Disposition: attachment; filename="skladki_2026-01.xlsx"

[Excel file binary data]
```

---

### Admin - Events

```http
GET /admin/kalendarz
```

**Description:** Event management dashboard

**Authentication:** Admin only

**Features:**
- List all events
- Create new events
- Edit events
- Delete events
- View RSVP list

---

### Admin - Create Event

```http
POST /admin/kalendarz/nowy
```

**Description:** Create new association event

**Authentication:** Admin only

**Request Body (Form):**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `title` | string | Yes | Event title |
| `description` | string | Yes | Event description |
| `event_date` | datetime | Yes | Event date and time |
| `location` | string | Yes | Event location |
| `max_attendees` | integer | No | Maximum attendees (null = unlimited) |

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/kalendarz

Flash: "Wydarzenie utworzone"
```

---

### Admin - Delete Event

```http
POST /admin/kalendarz/<event_id>/delete
```

**Description:** Delete event

**Authentication:** Admin only

**Warning:** Cascade deletes all RSVPs

**Response:**
```http
HTTP/1.1 302 Found
Location: /admin/kalendarz

Flash: "Wydarzenie usunięte"
```

---

### Admin - SEO Dashboard

```http
GET /admin/seo
```

**Description:** SEO audit management dashboard

**Authentication:** Admin only

**Features:**
- View all company SEO scores
- Filter by score range
- Sort by performance, SEO, accessibility
- Trigger audits
- View audit history

**Response:**
- HTML table with SEO metrics for all companies

---

### Admin - GBP Audit Dashboard

```http
GET /admin/gbp-audit
```

**Description:** Google Business Profile audit dashboard

**Authentication:** Admin only

**Features:**
- View GBP completeness scores
- Identify missing profiles
- Trigger audits
- View AI recommendations

---

### Admin - Social Media Dashboard

```http
GET /admin/social-media
```

**Description:** Social media profile audit dashboard

**Authentication:** Admin only

**Features:**
- Platform coverage statistics
- Missing profile identification
- Profile verification status
- Follower count tracking

**Response:**
- HTML dashboard with social media stats

---

### Admin - IT Audit Dashboard

```http
GET /admin/it-audit
```

**Description:** IT infrastructure audit overview

**Authentication:** Admin only

**Features:**
- IT maturity scores
- Security score distribution
- Collaboration readiness
- Potential collaboration matches

---

### Admin - Chat Analytics

```http
GET /admin/chat-analytics
```

**Description:** AI chat usage analytics

**Authentication:** Admin only

**Metrics:**
- Total conversations
- Total messages
- Total API cost
- Average cost per conversation
- Most active users
- Token usage trends

**Response:**
- HTML dashboard with charts and tables

---

### Admin - Debug Panel

```http
GET /admin/debug
```

**Description:** Real-time application log viewer

**Authentication:** Admin only

**Features:**
- Last 500 log entries
- In-memory log buffer
- Log level filtering
- Auto-refresh

**Response:**
- HTML page with log entries

---

### Admin - Digital Maturity

```http
GET /admin/digital-maturity
```

**Description:** Digital maturity overview for all companies

**Authentication:** Admin only

**Features:**
- Maturity score distribution
- Average scores by category
- Companies needing improvement
- Trends over time

---

### API - SEO Audit (List)

```http
GET /api/seo/audit
```

**Description:** Get SEO audit results

**Authentication:** Admin only

**Query Parameters:**

| Parameter | Type | Description |
|-----------|------|----------|
| `slug` | string | Filter by company slug |

**Response:**

```json
{
  "audits": [
    {
      "company_slug": "pixlab-sp-z-o-o",
      "company_name": "PIXLAB Sp. z o.o.",
      "overall_score": 85,
      "seo_score": 90,
      "performance_score": 80,
      "accessibility_score": 88,
      "best_practices_score": 85,
      "audited_at": "2026-01-10T10:00:00Z"
    }
  ],
  "total": 45
}
```

---

### API - SEO Audit (Get by Slug)

```http
GET /api/seo/audit/<slug>
```

**Description:** Get latest SEO audit for company

**Authentication:** Admin only

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `slug` | string | Company slug |

**Response:**

```json
{
  "company_slug": "pixlab-sp-z-o-o",
  "overall_score": 85,
  "seo_score": 90,
  "performance_score": 80,
  "accessibility_score": 88,
  "best_practices_score": 85,
  "pagespeed_seo_score": 92,
  "pagespeed_performance_score": 78,
  "on_page_seo_score": 88,
  "technical_seo_score": 90,
  "audited_at": "2026-01-10T10:00:00Z",
  "details": {
    "meta_tags": {...},
    "headings": {...},
    "images": {...},
    "links": {...}
  }
}
```

---

### API - SEO Audit (Trigger)

```http
POST /api/seo/audit
```

**Description:** Trigger SEO audit for company

**Authentication:** Admin only

**Rate Limit:** 10 requests/hour

**Request Body:**

```json
{
  "slug": "pixlab-sp-z-o-o"
}
```

**Workflow:**

```
1. Get company by slug
2. Extract website URL
3. Call Google PageSpeed Insights API (~20s)
4. Perform on-page SEO analysis
5. Perform technical SEO checks
6. Calculate composite score
7. Save to company_website_analysis table
8. Return results
```

**Response:**

```json
{
  "status": "success",
  "company_slug": "pixlab-sp-z-o-o",
  "overall_score": 85,
  "audit_id": 123,
  "audited_at": "2026-01-10T10:00:22Z"
}
```

**Error Response (Quota Exceeded):**

```json
{
  "status": "error",
  "error": "PageSpeed API quota exceeded",
  "retry_after": 3600
}
```

**Status Codes:**
- `200 OK` - Audit completed
- `400 Bad Request` - Invalid slug or missing URL
- `429 Too Many Requests` - Rate limit or API quota exceeded
- `500 Internal Server Error` - API error

---

### API - GBP Audit (Trigger)

```http
POST /api/gbp/audit
```

**Description:** Trigger Google Business Profile audit

**Authentication:** Admin only

**Rate Limit:** 10 requests/hour

**Request Body:**

```json
{
  "slug": "pixlab-sp-z-o-o"
}
```

**Response:**

```json
{
  "status": "success",
  "company_slug": "pixlab-sp-z-o-o",
  "completeness_score": 75,
  "recommendations": [
    "Dodaj więcej zdjęć (obecnie: 5, zalecane: 10)",
    "Uzupełnij godziny otwarcia",
    "Dodaj opis działalności"
  ],
  "audited_at": "2026-01-10T10:00:15Z"
}
```

---

### API - GBP Audit (Get by Slug)

```http
GET /api/gbp/audit/<slug>
```

**Description:** Get latest GBP audit for company

**Authentication:** Admin only

**Response:**

```json
{
  "company_slug": "pixlab-sp-z-o-o",
  "completeness_score": 75,
  "place_id": "ChIJ...",
  "has_name": true,
  "has_address": true,
  "has_phone": true,
  "has_website": true,
  "has_hours": false,
  "has_description": true,
  "photo_count": 5,
  "review_count": 12,
  "avg_rating": 4.5,
  "recommendations": [...],
  "audited_at": "2026-01-10T10:00:15Z"
}
```

---

### API - Social Media Audit

```http
POST /api/social/audit
```

**Description:** Trigger social media profile audit

**Authentication:** Admin only

**Request Body:**

```json
{
  "slug": "pixlab-sp-z-o-o"
}
```

**Response:**

```json
{
  "status": "success",
  "company_slug": "pixlab-sp-z-o-o",
  "platforms_found": {
    "facebook": true,
    "instagram": true,
    "linkedin": true,
    "youtube": false,
    "tiktok": false,
    "twitter": false
  },
  "coverage": 50,
  "audited_at": "2026-01-10T10:00:30Z"
}
```

---

## Audit Endpoints

### SEO Audit Report (Public)

```http
GET /audit/seo/<slug>
```

**Description:** Public SEO audit report for company

**Authentication:** None

**Path Parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `slug` | string | Company slug |

**Response:**
- HTML page with SEO audit results
- Scores, recommendations, performance metrics
- Public-facing (no admin controls)

**Example:**
```bash
curl https://nordabiznes.pl/audit/seo/pixlab-sp-z-o-o
```

---

### Social Media Audit Report (Public)

```http
GET /audit/social/<slug>
```

**Description:** Public social media profile report

**Authentication:** None

**Response:**
- HTML page showing social media presence
- Platform coverage, verified profiles
- Links to social media pages

---

### GBP Audit Report (Public)

```http
GET /audit/gbp/<slug>
```

**Description:** Public Google Business Profile audit

**Authentication:** None

**Response:**
- HTML page with GBP completeness score
- Missing fields
- Public recommendations

---

### IT Audit Report (Public)

```http
GET /audit/it/<slug>
```

**Description:** Public IT infrastructure audit

**Authentication:** None

**Response:**
- HTML page with IT maturity score
- Security score (high-level)
- Collaboration readiness
- Potential collaboration matches (anonymized)

---

## Error Codes

### HTTP Status Codes

| Code | Meaning | Usage |
|------|---------|-------|
| 200 OK | Success | Successful GET requests |
| 201 Created | Resource created | POST /api/chat/start |
| 302 Found | Redirect | After POST form submissions |
| 400 Bad Request | Invalid input | Validation errors |
| 401 Unauthorized | Not logged in | @login_required endpoints |
| 403 Forbidden | Insufficient permissions | Admin-only or ownership check |
| 404 Not Found | Resource not found | Invalid company slug, message ID |
| 429 Too Many Requests | Rate limit exceeded | 5/hour on auth endpoints, 10/hour on audits |
| 500 Internal Server Error | Server error | Unhandled exceptions, API failures |

### Error Response Format (JSON)

```json
{
  "error": "Error message",
  "code": "ERROR_CODE",
  "details": {...}
}
```

### Common Error Responses

**401 Unauthorized:**
```json
{
  "error": "Authentication required",
  "code": "UNAUTHORIZED",
  "redirect": "/login"
}
```

**403 Forbidden:**
```json
{
  "error": "Insufficient permissions",
  "code": "FORBIDDEN"
}
```

**404 Not Found:**
```json
{
  "error": "Resource not found",
  "code": "NOT_FOUND",
  "resource": "company",
  "slug": "invalid-slug"
}
```

**429 Rate Limit:**
```json
{
  "error": "Rate limit exceeded",
  "code": "RATE_LIMIT_EXCEEDED",
  "retry_after": 3600,
  "limit": "50/hour"
}
```

**500 Server Error:**
```json
{
  "error": "Internal server error",
  "code": "INTERNAL_ERROR",
  "request_id": "abc123"
}
```

---

## Examples

### Complete AI Chat Flow

```bash
# 1. Login
curl -c cookies.txt -X POST https://nordabiznes.pl/login \
  -d "email=test@nordabiznes.pl" \
  -d "password=&Rc2LdbSw&jiGR0ek@Bz"

# 2. Start conversation
CONV_ID=$(curl -b cookies.txt -X POST https://nordabiznes.pl/api/chat/start \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: $(getCsrfToken)" \
  -d '{"initial_message": "Szukam firm IT"}' | jq -r '.conversation_id')

# 3. Send message
curl -b cookies.txt -X POST https://nordabiznes.pl/api/chat/$CONV_ID/message \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: $(getCsrfToken)" \
  -d '{"message": "Kto tworzy strony www?"}' | jq

# 4. Get history
curl -b cookies.txt https://nordabiznes.pl/api/chat/$CONV_ID/history | jq
```

---

### Trigger SEO Audit

```bash
# 1. Login as admin
curl -c cookies.txt -X POST https://nordabiznes.pl/login \
  -d "email=testadmin@nordabiznes.pl" \
  -d "password=cSfQbbwegwv1v3Q2Dm0Q"

# 2. Trigger audit
curl -b cookies.txt -X POST https://nordabiznes.pl/api/seo/audit \
  -H "Content-Type: application/json" \
  -H "X-CSRFToken: $(getCsrfToken)" \
  -d '{"slug": "pixlab-sp-z-o-o"}' | jq

# 3. View public report
curl https://nordabiznes.pl/audit/seo/pixlab-sp-z-o-o
```

---

### Company Search with cURL

```bash
# Search by keyword
curl "https://nordabiznes.pl/search?q=strony+www"

# Search by NIP
curl "https://nordabiznes.pl/search?q=5882436505"

# Search with category filter
curl "https://nordabiznes.pl/search?q=budowa&category=2"
```

---

### Export Companies JSON

```bash
# All companies
curl https://nordabiznes.pl/api/companies | jq

# IT companies only
curl "https://nordabiznes.pl/api/companies?category=1" | jq

# Limit to 10 companies
curl "https://nordabiznes.pl/api/companies?limit=10" | jq
```

---

## Related Documentation

- **[Flask Components](./04-flask-components.md)** - Application architecture and route organization
- **[Authentication Flow](./flows/01-authentication-flow.md)** - Detailed authentication and session management
- **[AI Chat Flow](./flows/03-ai-chat-flow.md)** - Complete AI chat implementation
- **[SEO Audit Flow](./flows/04-seo-audit-flow.md)** - SEO audit workflow and API integration
- **[Security Architecture](./09-security-architecture.md)** - Security controls and best practices

---

## Maintenance Notes

### When to Update This Document

- **New endpoints added:** Add to appropriate section with full documentation
- **Authentication changes:** Update authentication section and affected endpoints
- **Rate limiting changes:** Update rate limiting section
- **New query parameters:** Add to endpoint documentation
- **Response format changes:** Update examples and schemas

### What NOT to Update

- **Business logic details:** Keep this in flow documentation
- **Database schema:** Keep in database schema documentation
- **Infrastructure details:** Keep in deployment/network documentation

### Review Frequency

- **Quarterly:** Review all endpoints for accuracy
- **After major features:** Update immediately
- **After API changes:** Update immediately

---

## Glossary

| Term | Definition |
|------|------------|
| **Endpoint** | HTTP route that accepts requests and returns responses |
| **Slug** | URL-friendly identifier (kebab-case, e.g., `pixlab-sp-z-o-o`) |
| **CSRF** | Cross-Site Request Forgery protection |
| **Rate Limiting** | Restriction on number of requests per time period |
| **Flash Message** | One-time user notification message |
| **Session** | Server-side user authentication state |
| **JWT** | JSON Web Token (not used in this application) |
| **API Key** | Authentication token for API access (not used in this application) |
| **RBAC** | Role-Based Access Control |

---

**Document Status:** Complete
**Coverage:** 90+ endpoints documented
**Completion Date:** 2026-01-10
**Next Review:** 2026-04-10

---

*This document provides a comprehensive reference for all HTTP endpoints in the Norda Biznes Hub application. It serves as the authoritative guide for developers, integrators, and system administrators working with the API.*
