diff --git a/app/api/etudiants.py b/app/api/etudiants.py
index 41a95760bfd8be605c78ff07c9f787e0ccc88892..264271cda96999deab86755a2e3952c48b977195 100755
--- a/app/api/etudiants.py
+++ b/app/api/etudiants.py
@@ -20,6 +20,7 @@ from sqlalchemy.dialects.postgresql import VARCHAR
 import app
 from app.api import api_bp as bp, api_web_bp
 from app.api import tools
+from app.but import bulletin_but_court
 from app.decorators import scodoc, permission_required
 from app.models import (
     Admission,
@@ -35,6 +36,7 @@ from app.scodoc.sco_permissions import Permission
 from app.scodoc.sco_utils import json_error, suppress_accents
 
 import app.scodoc.sco_photos as sco_photos
+import app.scodoc.sco_utils as scu
 
 # Un exemple:
 # @bp.route("/api_function/<int:arg>")
@@ -364,7 +366,7 @@ def bulletin(
     formsemestre_id : l'id d'un formsemestre
     code_type : "etudid", "nip" ou "ine"
     code : valeur du code INE, NIP ou etudid, selon code_type.
-    version : type de bulletin (par défaut, "long"): short, long, long_mat
+    version : type de bulletin (par défaut, "long"): short, long, selectedevals, butcourt
     pdf : si spécifié, bulletin au format PDF (et non JSON).
 
     Exemple de résultat : voir https://scodoc.org/ScoDoc9API/#bulletin
@@ -372,6 +374,8 @@ def bulletin(
     if version == "pdf":
         version = "long"
         pdf = True
+    if version not in scu.BULLETINS_VERSIONS_BUT:
+        return json_error(404, "version invalide")
     # return f"{code_type}={code}, version={version}, pdf={pdf}"
     formsemestre = FormSemestre.query.filter_by(id=formsemestre_id).first_or_404()
     dept = Departement.query.filter_by(id=formsemestre.dept_id).first_or_404()
@@ -394,6 +398,12 @@ def bulletin(
     etud = query.first()
     if etud is None:
         return json_error(404, message="etudiant inexistant")
+
+    if version == "butcourt":
+        if pdf:
+            return bulletin_but_court.bulletin_but(formsemestre_id, etud.id, fmt="pdf")
+        else:
+            return json_error(404, message="butcourt available only in pdf")
     if pdf:
         pdf_response, _ = do_formsemestre_bulletinetud(
             formsemestre,
diff --git a/app/but/bulletin_but.py b/app/but/bulletin_but.py
index 494fe090bb519eab9f8ccf22aaaffaba9bbe98bd..8bdab7b48fdc6c940e870fd158d870b7dcc28569 100644
--- a/app/but/bulletin_but.py
+++ b/app/but/bulletin_but.py
@@ -24,6 +24,7 @@ from app.scodoc import codes_cursus
 from app.scodoc import sco_groups
 from app.scodoc import sco_preferences
 from app.scodoc.codes_cursus import UE_SPORT, DEF
+from app.scodoc.sco_exceptions import ScoValueError
 from app.scodoc.sco_utils import fmt_note
 
 
@@ -344,6 +345,8 @@ class BulletinBUT:
         - Si force_publishing, rempli le bulletin même si bul_hide_xml est vrai
         (bulletins non publiés).
         """
+        if version not in scu.BULLETINS_VERSIONS:
+            raise ScoValueError("version de bulletin demandée invalide")
         res = self.res
         formsemestre = res.formsemestre
         etat_inscription = etud.inscription_etat(formsemestre.id)
diff --git a/app/but/bulletin_but_court.py b/app/but/bulletin_but_court.py
index f88b319f5bbd6a95241c0b84364a25e16ab0da97..2c326177c5d60aa4eeeac9c543c95f5fd342a578 100644
--- a/app/but/bulletin_but_court.py
+++ b/app/but/bulletin_but_court.py
@@ -115,5 +115,6 @@ def bulletin_but(formsemestre_id: int, etudid: int = None, fmt="html"):
         datetime=datetime,
         sco=ScoData(formsemestre=formsemestre, etud=etud),
         time=time,
+        version="butcourt",
         **args,
     )
diff --git a/app/models/formsemestre.py b/app/models/formsemestre.py
index f4a4ea9c156fbe05f55db6d07d6cf8e1285901cf..970272be74ed40f7978134ebca8dcc0225018757 100644
--- a/app/models/formsemestre.py
+++ b/app/models/formsemestre.py
@@ -775,11 +775,20 @@ class FormSemestre(db.Model):
             etuds.sort(key=lambda e: e.sort_key)
         return etuds
 
-    def get_partitions_list(self, with_default=True) -> list[Partition]:
+    def get_partitions_list(
+        self, with_default=True, only_listed=False
+    ) -> list[Partition]:
         """Liste des partitions pour ce semestre (list of dicts),
         triées par numéro, avec la partition par défaut en fin de liste.
         """
-        partitions = [p for p in self.partitions if p.partition_name is not None]
+        if only_listed:
+            partitions = [
+                p
+                for p in self.partitions
+                if p.partition_name is not None and p.show_in_lists
+            ]
+        else:
+            partitions = [p for p in self.partitions if p.partition_name is not None]
         if with_default:
             partitions += [p for p in self.partitions if p.partition_name is None]
         return partitions
diff --git a/app/scodoc/sco_archives.py b/app/scodoc/sco_archives.py
index 789509c3f53d793ae42a66a7852f9836aba6b6b4..e296316ce23050d9f70c3fafb5420da80ac21637 100644
--- a/app/scodoc/sco_archives.py
+++ b/app/scodoc/sco_archives.py
@@ -344,6 +344,8 @@ def do_formsemestre_archive(
         gen_formsemestre_recapcomplet_json,
     )
 
+    if bul_version not in scu.BULLETINS_VERSIONS:
+        raise ScoValueError("version de bulletin demandée invalide")
     formsemestre = FormSemestre.get_formsemestre(formsemestre_id)
     res: NotesTableCompat = res_sem.load_formsemestre_results(formsemestre)
     sem_archive_id = formsemestre_id
@@ -537,7 +539,7 @@ enregistrés et non modifiables, on peut les retrouver ultérieurement.
                     "Version intermédiaire",
                     "Version complète",
                 ],
-                "allowed_values": scu.BULLETINS_VERSIONS,
+                "allowed_values": scu.BULLETINS_VERSIONS.keys(),
                 "default": "long",
             },
         ),
diff --git a/app/scodoc/sco_bulletins_generator.py b/app/scodoc/sco_bulletins_generator.py
index 2ec0e23950356634005c2af961d83f193275439a..4d76712d7990e8dee7e0268493915a0cfbda05e2 100644
--- a/app/scodoc/sco_bulletins_generator.py
+++ b/app/scodoc/sco_bulletins_generator.py
@@ -283,7 +283,6 @@ def make_formsemestre_bulletin_etud(
 
     formsemestre_id = bul_dict["formsemestre_id"]
     bul_class_name = sco_preferences.get_preference("bul_class_name", formsemestre_id)
-
     gen_class = None
     for bul_class_name in (
         sco_preferences.get_preference("bul_class_name", formsemestre_id),
diff --git a/app/scodoc/sco_bulletins_json.py b/app/scodoc/sco_bulletins_json.py
index df54776949d3f567049be75e58b737ac2d30973f..7676ac162d643c7aab780860e03dce43a919cf07 100644
--- a/app/scodoc/sco_bulletins_json.py
+++ b/app/scodoc/sco_bulletins_json.py
@@ -85,7 +85,7 @@ def formsemestre_bulletinetud_published_dict(
     etudid,
     force_publishing=False,
     xml_nodate=False,
-    xml_with_decisions=False,  # inclue les decisions même si non publiées
+    xml_with_decisions=False,  # inclure les décisions même si non publiées
     version="long",
 ) -> dict:
     """Dictionnaire representant les informations _publiees_ du bulletin de notes
@@ -95,8 +95,8 @@ def formsemestre_bulletinetud_published_dict(
         short (sans les évaluations)
         long  (avec les évaluations)
 
-        short_mat (sans évaluations, et structuration en matières)
-        long_mat  (avec évaluations, et structuration en matières)
+        # non implémenté: short_mat (sans évaluations, et structuration en matières)
+        #                 long_mat  (avec évaluations, et structuration en matières)
     """
     from app.scodoc import sco_bulletins
 
diff --git a/app/scodoc/sco_bulletins_pdf.py b/app/scodoc/sco_bulletins_pdf.py
index 61a44cf0061287805691ca0eceb0f33f55c6f2cb..5ccb6c9f3458269402034f7f2030eb51c94088f1 100644
--- a/app/scodoc/sco_bulletins_pdf.py
+++ b/app/scodoc/sco_bulletins_pdf.py
@@ -215,6 +215,8 @@ def get_formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"):
     "Document pdf avec tous les bulletins du semestre, et filename"
     from app.scodoc import sco_bulletins
 
+    if version not in scu.BULLETINS_VERSIONS:
+        raise ScoValueError("version de bulletin demandée invalide")
     cached = sco_cache.SemBulletinsPDFCache.get(str(formsemestre_id) + "_" + version)
     if cached:
         return cached[1], cached[0]
diff --git a/app/scodoc/sco_preferences.py b/app/scodoc/sco_preferences.py
index ea95821f789280ef8707f2f37b216a9c1d8bc6b7..eb82de4c332295e75199de035b5fa084d8ddc9ae 100644
--- a/app/scodoc/sco_preferences.py
+++ b/app/scodoc/sco_preferences.py
@@ -1317,7 +1317,7 @@ class BasePreferences:
                     "labels": sco_bulletins_generator.bulletin_class_descriptions(),
                     "allowed_values": sco_bulletins_generator.bulletin_class_names(),
                     "title": "Format des bulletins",
-                    "explanation": "format de présentation des bulletins de note (web et pdf)",
+                    "explanation": "format de présentation des bulletins de note (web et pdf), non utilisé en BUT.",
                     "category": "bul",
                 },
             ),
diff --git a/app/scodoc/sco_utils.py b/app/scodoc/sco_utils.py
index 7a93198e7425a02b90bee533e840c7d875d86f68..31ff703ed48da68c1990857b9c80daf1c51f9229 100644
--- a/app/scodoc/sco_utils.py
+++ b/app/scodoc/sco_utils.py
@@ -639,9 +639,16 @@ def get_mime_suffix(format_code: str) -> tuple[str, str]:
 TYPE_ADMISSION_DEFAULT = "Inconnue"
 TYPES_ADMISSION = (TYPE_ADMISSION_DEFAULT, "APB", "APB-PC", "CEF", "Direct")
 
-BULLETINS_VERSIONS = ("short", "selectedevals", "long")
+BULLETINS_VERSIONS = {
+    "short": "Version courte",
+    "selectedevals": "Version intermédiaire",
+    "long": "Version complète",
+}
+BULLETINS_VERSIONS_BUT = BULLETINS_VERSIONS | {
+    "butcourt": "Version courte spéciale BUT"
+}
 
-# Support for ScoDoc7 compatibility
+# -----  Support for ScoDoc7 compatibility
 
 
 def ScoURL():
diff --git a/app/static/css/scodoc.css b/app/static/css/scodoc.css
index c4d760e2df7dfb932210f0d8e0a780854529dca5..c31d0de60553a393de7113a959f495c6e40c00de 100644
--- a/app/static/css/scodoc.css
+++ b/app/static/css/scodoc.css
@@ -3078,11 +3078,17 @@ a.bull_link:hover {
 div.bulletin_menubar {
   padding-left: 25px;
 }
-
+div.bull_titre_semestre {
+  margin-top: 8px;
+  margin-bottom: 8px;
+  font-size: 120%;
+}
+div.bull_titre_semestre .parcours {
+  margin-left: 12px;
+}
 .bull_liensemestre {
   font-weight: bold;
 }
-
 .bull_liensemestre a {
   color: rgb(255, 0, 0);
   text-decoration: none;
diff --git a/app/templates/bul_head.j2 b/app/templates/bul_head.j2
index 6c284062e642df630256cb1d21f2703a4a808553..91acfb3d9eeadeec7fc77868a104a002d1386b51 100644
--- a/app/templates/bul_head.j2
+++ b/app/templates/bul_head.j2
@@ -14,21 +14,32 @@
         <input type="hidden" name="formsemestre_id" value="{{formsemestre.id}}"></input>
         <input type="hidden" name="etudid" value="{{etud.id}}"></input>
         <input type="hidden" name="fmt" value="{{fmt}}"></input>
-        Bulletin 
-        <span class="bull_liensemestre">
-        {{formsemestre.html_link_status() | safe}}
-        </span>
-        
+        <div class="bull_titre_semestre">
+            Bulletin
+            <span class="bull_liensemestre">
+            {{formsemestre.html_link_status() | safe}}
+            {% if formsemestre.etuds_inscriptions[etud.id].parcour %}
+                <span class="parcours">Parcours {{formsemestre.etuds_inscriptions[etud.id].parcour.code}}</span>
+            {% endif %}
+            </span>
+        </div>
         <div>
         <em>établi le {{time.strftime("%d/%m/%Y à %Hh%M")}} (notes sur 20)</em>
         <span class="rightjust">
-            <select name="version" onchange="document.f.submit()" class="noprint">
-                {% for (v, e) in (
-                    ("short", "Version courte"),
-                    ("selectedevals", "Version intermédiaire"),
-                    ("long", "Version complète"),
-                ) %}
-                <option value="{{v}}" {% if (v == version) %}selected{% endif %}>{{e}}</option>
+            <select name="version" onchange="self.location.href='{{
+                url_for('notes.formsemestre_bulletinetud',
+                    scodoc_dept=g.scodoc_dept,
+                    formsemestre_id=formsemestre.id,
+                    etudid=etud.id,
+                    )
+                }}&version='+this.value;"" class="noprint">
+                {% if formsemestre.formation.is_apc() %}
+                    {% set menu_items = scu.BULLETINS_VERSIONS_BUT.items() %}
+                {% else %}
+                    {% set menu_items = scu.BULLETINS_VERSIONS.items() %}
+                {% endif %}
+                {% for (v, e) in menu_items %}
+                    <option value="{{v}}" {% if (v == version) %}selected{% endif %}>{{e}}</option>
                 {% endfor %}
             </select>
         </span>
@@ -46,13 +57,15 @@
         </div>
         {% if formsemestre.formation.is_apc() %}
         <div>
-            <a style="margin-left: 32px;" class="stdlink"
-            href="{{url_for(
-                'notes.bulletin_but_html',
-                scodoc_dept=g.scodoc_dept,
-                formsemestre_id=formsemestre.id,
-                etudid=etud.id
-            )}}">version courte spéciale BUT</a>
+            {% if version != "butcourt" %}
+                <a style="margin-left: 32px;" class="stdlink"
+                href="{{url_for(
+                    'notes.bulletin_but_html',
+                    scodoc_dept=g.scodoc_dept,
+                    formsemestre_id=formsemestre.id,
+                    etudid=etud.id
+                )}}">version courte spéciale BUT</a>
+            {% endif %}
             <a style="margin-left: 32px;" class="stdlink"
             href="{{url_for('notes.validation_rcues', 
                 scodoc_dept=g.scodoc_dept, etudid=etud.id, 
diff --git a/app/templates/but/bulletin_court_page.j2 b/app/templates/but/bulletin_court_page.j2
index 2533684756921fc87d91a3b510f17330722343d7..730ba2b89a869be8f7b0d85116e5ca323c76ba37 100644
--- a/app/templates/but/bulletin_court_page.j2
+++ b/app/templates/but/bulletin_court_page.j2
@@ -39,40 +39,10 @@
 {%- endmacro %}
 
 {% block app_content %}
-<div class="but_bul_court_links">
-    <a href="{{url_for(
-            'notes.bulletin_but_pdf', scodoc_dept=g.scodoc_dept, etudid=etud.id, 
-            formsemestre_id=formsemestre.id
-        )}}" class="stdlink">version pdf {{scu.ICON_PDF|safe}}</a>
-    <a style="margin-left: 32px;"
-        href="{{url_for(
-            'notes.formsemestre_bulletinetud', 
-            scodoc_dept=g.scodoc_dept, etudid=etud.id, 
-            formsemestre_id=formsemestre.id
-    )}}" class="stdlink">version complète</a>
-    <a style="margin-left: 32px;" class="stdlink"
-        href="{{url_for('notes.validation_rcues', 
-            scodoc_dept=g.scodoc_dept, etudid=etud.id, 
-            formsemestre_id=formsemestre.id
-        )}}">visualiser les compétences BUT</a>
-</div>
-<div class="but_bul_court">
-    <div id="infos_etudiant">
-        <div class="nom">{{etud.nomprenom}}</div>
-        <div class="formation">BUT {{formsemestre.formation.referentiel_competence.specialite}}</div>
-        {% if formsemestre.etuds_inscriptions[etud.id].parcour %}
-            <div class="parcours">Parcours {{formsemestre.etuds_inscriptions[etud.id].parcour.code}}</div>
-        {% endif %}
-        <div class="annee_scolaire">Année {{formsemestre.annee_scolaire_str()}}</div>
-        <div class="semestre">Semestre {{formsemestre.semestre_id}}</div>
-    </div>
 
-    <div id="logo">
-        <a href="{{
-            url_for('scolar.ficheEtud', scodoc_dept=g.scodoc_dept, etudid=etud.id)
-        }}">{{etud.photo_html()|safe}}</a>
-    </div>
+{% include 'bul_head.j2' %}
 
+<div class="but_bul_court">
     {% if bul.options.show_abs %}
         <div id="assiduite">
             <div class="ligne-entete">Absences {{bul.semestre.absences.metrique}}</div>
diff --git a/app/views/notes.py b/app/views/notes.py
index d0063b6547df36ebe1de3d61be9786eb7c5100f6..c7a4613b04b0173d6d37e98a69f40ab63dd0f864 100644
--- a/app/views/notes.py
+++ b/app/views/notes.py
@@ -289,6 +289,8 @@ def formsemestre_bulletinetud(
     code_ine=None,
 ):
     fmt = fmt or "html"
+    if version not in scu.BULLETINS_VERSIONS_BUT:
+        raise ScoValueError("version de bulletin demandée invalide")
     if not isinstance(etudid, int):
         raise ScoInvalidIdType("formsemestre_bulletinetud: etudid must be an integer !")
     if formsemestre_id is not None and not isinstance(formsemestre_id, int):
@@ -312,6 +314,15 @@ def formsemestre_bulletinetud(
         raise ScoValueError(
             "Paramètre manquant: spécifier etudid, code_nip ou code_ine"
         )
+    if version == "butcourt":
+        return redirect(
+            url_for(
+                "notes.bulletin_but_pdf" if fmt == "pdf" else "notes.bulletin_but_html",
+                scodoc_dept=g.scodoc_dept,
+                etudid=etud.id,
+                formsemestre_id=formsemestre_id,
+            )
+        )
     if fmt == "json":
         return sco_bulletins.get_formsemestre_bulletin_etud_json(
             formsemestre, etud, version=version, force_publishing=force_publishing
@@ -1852,6 +1863,8 @@ sco_publish(
 @scodoc7func
 def formsemestre_bulletins_pdf(formsemestre_id, version="selectedevals"):
     "Publie les bulletins dans un classeur PDF"
+    if version not in scu.BULLETINS_VERSIONS:
+        raise ScoValueError("version de bulletin demandée invalide")
     pdfdoc, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
         formsemestre_id, version=version
     )
@@ -1871,7 +1884,7 @@ _EXPL_BULL = """Versions des bulletins:
 @permission_required(Permission.ScoView)
 @scodoc7func
 def formsemestre_bulletins_pdf_choice(formsemestre_id, version=None):
-    """Choix version puis envois classeur bulletins pdf"""
+    """Choix version puis envoi classeur bulletins pdf"""
     if version:
         pdfdoc, filename = sco_bulletins_pdf.get_formsemestre_bulletins_pdf(
             formsemestre_id, version=version
@@ -1890,6 +1903,8 @@ def formsemestre_bulletins_pdf_choice(formsemestre_id, version=None):
 @scodoc7func
 def etud_bulletins_pdf(etudid, version="selectedevals"):
     "Publie tous les bulletins d'un etudiants dans un classeur PDF"
+    if version not in scu.BULLETINS_VERSIONS:
+        raise ScoValueError("version de bulletin demandée invalide")
     pdfdoc, filename = sco_bulletins_pdf.get_etud_bulletins_pdf(etudid, version=version)
     return scu.sendPDFFile(pdfdoc, filename)
 
diff --git a/tests/api/test_api_etudiants.py b/tests/api/test_api_etudiants.py
index 41301059d3ca4dc982b037d1d2fcfa0054450729..e66490fc35d85481761d08624cc903481bdd9af6 100644
--- a/tests/api/test_api_etudiants.py
+++ b/tests/api/test_api_etudiants.py
@@ -762,6 +762,29 @@ def test_etudiant_bulletin_semestre(api_headers):
     bul = r.json()
     assert len(bul) == 14  # HARDCODED
 
+    ######## Bulletin BUT court en pdf #########
+    r = requests.get(
+        API_URL + "/etudiant/ine/" + str(INE) + "/formsemestre/1/bulletin/butcourt/pdf",
+        headers=api_headers,
+        verify=CHECK_CERTIFICATE,
+        timeout=scu.SCO_TEST_API_TIMEOUT,
+    )
+    assert r.status_code == 200
+    assert r.content[:4] == b"%PDF"
+
+    ######## Bulletin BUT format intermédiaire en pdf #########
+    r = requests.get(
+        API_URL
+        + "/etudiant/ine/"
+        + str(INE)
+        + "/formsemestre/1/bulletin/selectedevals/pdf",
+        headers=api_headers,
+        verify=CHECK_CERTIFICATE,
+        timeout=scu.SCO_TEST_API_TIMEOUT,
+    )
+    assert r.status_code == 200
+    assert r.content[:4] == b"%PDF"
+
     ################### LONG + PDF #####################
 
     # ######### Test etudid #########