Yes—this is a clean, very doable setup. I’ll give you a working example with:

* MySQL table structure
* PHP API endpoint
* Email alert logic
* JavaScript call to the API

You can adapt naming to your LMS later.

---

# 1. Database Structure (MySQL)

You’ll need something like this:

```sql
CREATE TABLE organisations (
    id INT PRIMARY KEY AUTO_INCREMENT,
    name VARCHAR(255),
    is_active TINYINT(1) DEFAULT 1
);

CREATE TABLE badges (
    id INT PRIMARY KEY AUTO_INCREMENT,
    code VARCHAR(100) UNIQUE
);

CREATE TABLE organisation_badges (
    id INT PRIMARY KEY AUTO_INCREMENT,
    organisation_id INT,
    badge_id INT,
    is_current TINYINT(1) DEFAULT 1,
    FOREIGN KEY (organisation_id) REFERENCES organisations(id),
    FOREIGN KEY (badge_id) REFERENCES badges(id)
);
```

---

# 2. Folder Structure

```
/api/
    getBadge.php
/badges/
    badge1_s.png
    badge1_m.png
    badge1_l.png
```

---

# 3. PHP API Endpoint (`getBadge.php`)

```php
<?php
// Database connection
$mysqli = new mysqli("localhost", "username", "password", "database");

if ($mysqli->connect_error) {
    http_response_code(500);
    exit("Database connection failed");
}

// Get parameters
$orgId = $_GET['organisation_id'] ?? null;
$badgeCode = $_GET['badge_code'] ?? null;
$size = $_GET['size'] ?? 'm';

// Validate size
$allowedSizes = ['s', 'm', 'l'];
if (!in_array($size, $allowedSizes)) {
    http_response_code(400);
    exit("Invalid size");
}

if (!$orgId || !$badgeCode) {
    http_response_code(400);
    exit("Missing parameters");
}

// Prepare query
$stmt = $mysqli->prepare("
    SELECT o.name, ob.is_current
    FROM organisations o
    JOIN organisation_badges ob ON o.id = ob.organisation_id
    JOIN badges b ON b.id = ob.badge_id
    WHERE o.id = ? AND b.code = ?
");

$stmt->bind_param("is", $orgId, $badgeCode);
$stmt->execute();
$result = $stmt->get_result();

if ($row = $result->fetch_assoc()) {

    if ($row['is_current']) {

        // Build image path
        $filePath = "../badges/" . $badgeCode . "_" . $size . ".png";

        if (file_exists($filePath)) {
            header("Content-Type: image/png");
            readfile($filePath);
            exit;
        } else {
            http_response_code(404);
            exit("Image not found");
        }

    } else {
        // Send alert email
        $to = "admin@yourdomain.com";
        $subject = "Badge Access Attempt - Not Current";
        $message = "Organisation: " . $row['name'] . "\nBadge: " . $badgeCode;
        $headers = "From: no-reply@yourdomain.com";

        mail($to, $subject, $message, $headers);

        http_response_code(204); // No content
        exit;
    }

} else {
    http_response_code(404);
    exit("Not found");
}

$stmt->close();
$mysqli->close();
?>
```

---

# 4. JavaScript API Call

```javascript
function loadBadge(orgId, badgeCode, size) {
    const url = `/api/getBadge.php?organisation_id=${orgId}&badge_code=${badgeCode}&size=${size}`;

    fetch(url)
        .then(response => {
            if (response.status === 200) {
                return response.blob();
            } else if (response.status === 204) {
                console.log("Organisation not current for this badge");
                return null;
            } else {
                throw new Error("Error fetching badge");
            }
        })
        .then(blob => {
            if (blob) {
                const imgUrl = URL.createObjectURL(blob);
                document.getElementById("badgeImg").src = imgUrl;
            }
        })
        .catch(err => console.error(err));
}
```

### HTML Example

```html
<img id="badgeImg" />
```

---

# 5. Important Improvements (Highly Recommended)

### 🔒 Security

* Use POST instead of GET for production
* Add an API key or token
* Sanitize inputs (you’re mostly safe with prepared statements already)

### 📧 Email reliability

PHP `mail()` is unreliable. Consider:

* SMTP via PHPMailer
* Or services like SendGrid

### ⚡ Performance

* Add caching headers for images
* Consider storing image paths in DB if dynamic

### 🧠 Optional Enhancement

Instead of returning *nothing* for invalid orgs, you could return a default “expired badge” image—better UX.

---

# 6. Quick Example Call

```javascript
loadBadge(3, 'first_aid', 'm');
```

---

If you want, I can extend this to:

* integrate into your LMS structure
* add authentication tokens
* generate signed badge URLs (so people can’t fake requests)
* or log all badge access attempts for reporting

Just tell me 👍
