diff --git a/src/Controller/ApiLexiconController.php b/src/Controller/ApiLexiconController.php
index a1b6109a3185dcc4f28e6f6bd372efe23c0e26fe..68f411035d93623d0a9413060fb1cb8c8413a7e7 100644
--- a/src/Controller/ApiLexiconController.php
+++ b/src/Controller/ApiLexiconController.php
@@ -132,7 +132,7 @@ class ApiLexiconController extends ApiBaseController
     /**
      * Récupère un nombre n de graphies d’un lexique
      *
-     * @Route("/extract/{nb}", name="api_lexicon_extract_graphies", methods={"GET"})
+     * @Route("/extract/{nb}", name="api_lexicon_extract_graphies", methods={"GET"}, requirements={"id" = "\d+"})
      * @OA\Parameter(name="nb", in="path", description="nb de graphies retournées", @OA\Schema(type="integer"))
      * @OA\Parameter(name="lexiconId", in="query", required=true, description="id du lexique dans lequel chercher", @OA\Schema(type="string"))
      *
@@ -163,7 +163,7 @@ class ApiLexiconController extends ApiBaseController
             }
         }
         shuffle($graphies);
-        $selectedGraphies = array_slice($graphies, 0, $nb);
+        $selectedGraphies = $nb > 0 ? array_slice($graphies, 0, $nb) : $graphies;
 
         return $this->createJsonResponse(200, $selectedGraphies);
     }
@@ -257,4 +257,75 @@ class ApiLexiconController extends ApiBaseController
 
         return $this->createJsonResponse();
     }
+
+    /**
+     * Recherche de lexiques par catégorie ou id user ou id groupe ou langue
+     *
+     * @Route("/search", name="api_lexicon_search", methods={"GET"})
+     *
+     * @OA\Response(response=200, description="success",
+     *      @OA\JsonContent(type="array",
+     *          @OA\Items(ref=@Model(type=Lexicon::class, groups={"lexicon:read"})))
+     * )
+     * @OA\Response(response=401, description="error", @OA\JsonContent(type="string"))
+     * @OA\Response(response=403, description="error", @OA\JsonContent(type="string"))
+     * @OA\Response(response=500, description="error", @OA\JsonContent(type="string"))
+     *
+     * @OA\Parameter(name="user_id", in="query", @OA\Schema(type="integer", example="4"))
+     * @OA\Parameter(name="group_id", in="query", @OA\Schema(type="integer", example="1"))
+     * @OA\Parameter(name="category", in="query", @OA\Schema(type="string", example="User ou Group ou Zero ou New words"))
+     * @OA\Parameter(name="language", in="query", @OA\Schema(type="string", example="en"))
+     *
+     * @OA\Tag(name="Lexicons")
+     * @Security(name="OAuth2")
+     */
+    public function search(Request $request, SerializerInterface $serializer): Response
+    {
+        $userId    = $request->get('user_id');
+        $groupId   = $request->get('group_id');
+        $category  = $request->get('category');
+        $language  = $request->get('language');
+        if (!$groupId && !$category && !$userId && !$language) {
+            return $this->createJsonResponse(401, ['error' => sprintf("Veuillez spécifier au moins un paramètre de recherche parmi: group_id, category, user_id, language")]);
+        }
+        if ($category && !in_array($category, Lexicon::LEXICON_TYPES)) {
+            return $this->createJsonResponse(401, ['error' => sprintf("La catégorie de lexique %s n'existe pas", $category)]);
+        }
+        if ($language && !in_array($language, $this->getLanguages())) {
+            return $this->createJsonResponse(401, ['error' => sprintf("Pas de langue trouvée pour: %s", $language)]);
+        }
+
+        $filter = [];
+        if ($userId ?? null) {
+            $user = $this->doctrine->getRepository(User::class)->find($userId);
+            if (!$user) {
+                return $this->createJsonResponse(401, ['error' => sprintf("Pas d'utilisateur trouvé pour l'id %s", $userId)]);
+            } else {
+                $filter['user'] = $user;
+            }
+        }
+        if ($groupId ?? null) {
+            $group = $this->doctrine->getRepository(User::class)->find($groupId);
+            if (!$group) {
+                return $this->createJsonResponse(401, ['error' => sprintf("Pas de groupe trouvé pour l'id %s", $groupId)]);
+            } else {
+                $filter['group'] = $group;
+            }
+        }
+        if ($category ?? null) {
+            $filter['category'] = $category;
+        }
+        if ($language ?? null) {
+            $filter['language'] = $language;
+        }
+
+        $lexicons = $this->doctrine->getRepository(Lexicon::class)->search($filter);
+
+        $content = $serializer->serialize($lexicons, 'json', [
+            'groups' => ["lexicon:read", "user:read", "group:read"],
+            'datetime_format' => 'Y-m-d h:i:s.u'
+        ]);
+
+        return new JsonResponse($content, 200, [], true);
+    }
 }
diff --git a/src/Controller/ApiTraceController.php b/src/Controller/ApiTraceController.php
index 5e912e3d8094c194c910abe79eb9193d17543481..043f1bce0aaef5d459996c38c2c19223a354a1c7 100644
--- a/src/Controller/ApiTraceController.php
+++ b/src/Controller/ApiTraceController.php
@@ -163,9 +163,9 @@ class ApiTraceController extends ApiBaseController
      *
      * @OA\Parameter(name="date", in="query", @OA\Schema(type="date", example="2023-01-09"))
      * @OA\Parameter(name="date_client", in="query", @OA\Schema(type="date", example="2023-01-09"))
-     * @OA\Parameter(name="user_id", in="query", @OA\Schema(type="date", example="4"))
-     * @OA\Parameter(name="origin", in="query", @OA\Schema(type="date", example="Prisms"))
-     * @OA\Parameter(name="action", in="query", @OA\Schema(type="date", example="action"))
+     * @OA\Parameter(name="user_id", in="query", @OA\Schema(type="integer", example="4"))
+     * @OA\Parameter(name="origin", in="query", @OA\Schema(type="string", example="Prisms"))
+     * @OA\Parameter(name="action", in="query", @OA\Schema(type="string", example="action"))
      *
      * @OA\Tag(name="Traces")
      * @Security(name="OAuth2")
diff --git a/src/Entity/Group.php b/src/Entity/Group.php
index cc5ce1b9649931f5783280354de5e652130a42a0..c9506a09e76fd7347e865681494b587cef99ca19 100644
--- a/src/Entity/Group.php
+++ b/src/Entity/Group.php
@@ -20,6 +20,7 @@ class Group
      * @ORM\Id
      * @ORM\GeneratedValue
      * @ORM\Column(type="integer")
+     * @Groups({"group:read"})
      */
     private $id;
 
@@ -43,6 +44,7 @@ class Group
      * @ORM\Column(type="string", length=150)
      * @Assert\Length(max={150})
      * @Assert\NotBlank()
+     * @Groups({"group:read"})
      */
     private $name;
 
diff --git a/src/Entity/Lexicon.php b/src/Entity/Lexicon.php
index 8d4b5e8b13784d66486ce51eb3d08c88153776c4..ab29022759cf715ba54b185cd979ac48ed576677 100644
--- a/src/Entity/Lexicon.php
+++ b/src/Entity/Lexicon.php
@@ -22,6 +22,13 @@ class Lexicon
     const TYPE_ZERO       = 'Zero';
     const TYPE_NEW_WORDS  = 'New words';
 
+    const LEXICON_TYPES = [
+        self::TYPE_USER,
+        self::TYPE_GROUP,
+        self::TYPE_ZERO,
+        self::TYPE_NEW_WORDS,
+    ];
+
     const MERGE_MERGE     = 'merge';
     const MERGE_OVERWRITE = 'overwrite';
     const MERGE_IGNORE    = 'ignore';
@@ -50,6 +57,7 @@ class Lexicon
 
     /**
      * @ORM\Column(type="string", length=100)
+     * @Groups({"lexicon:read"})
      */
     private $language;
 
diff --git a/src/Normalizer/ApiProblemNormalizer.php b/src/Normalizer/ApiProblemNormalizer.php
index ef459c083b764121aedab08d8ca93656584d12fc..d86a768be1bc7226d5a08c4c84e126211dc27fc0 100644
--- a/src/Normalizer/ApiProblemNormalizer.php
+++ b/src/Normalizer/ApiProblemNormalizer.php
@@ -22,8 +22,14 @@ class ApiProblemNormalizer implements NormalizerInterface
 
     public function normalize($exception, string $format = null, array $context = []): array
     {
+        if ($exception->getStatusCode() === 404) {
+            return [
+                'error' => 'Resource not found. Check uri and parameters.',
+            ];
+        }
+
         return [
-            'error' => 'Something went wrong. Please try again later.',
+            'error' => sprintf('%s : Something went wrong. Please try again later.', $exception->getStatusCode()),
         ];
     }
 
diff --git a/src/Repository/LexiconRepository.php b/src/Repository/LexiconRepository.php
index 64f31f0b57c22500f479c941d81996a81e9e0734..4285935340c8dbc21a37e6a9650929abf522b82c 100644
--- a/src/Repository/LexiconRepository.php
+++ b/src/Repository/LexiconRepository.php
@@ -21,6 +21,41 @@ class LexiconRepository extends ServiceEntityRepository
         parent::__construct($registry, Lexicon::class);
     }
 
+    public function search($filter)
+    {
+        $qb = $this->createQueryBuilder('l')
+            ->leftJoin('l.user', 'u')
+            ->leftJoin('l.group', 'g')
+        ;
+
+        if ($filter['user'] ?? null) {
+            $qb->andWhere('u = :user')
+                ->setParameter('user', $filter['user'])
+            ;
+        }
+
+        if ($filter['group'] ?? null) {
+            $qb->andWhere('g = :group')
+                ->setParameter('group', $filter['group'])
+            ;
+        }
+
+        if ($filter['category'] ?? null) {
+            $qb->andWhere('l.category = :category')
+                ->setParameter('category', $filter['category'])
+            ;
+        }
+
+        if ($filter['language'] ?? null) {
+            $qb->andWhere('l.language = :language')
+                ->setParameter('language', $filter['language'])
+            ;
+        }
+
+        return $qb->getQuery()->getResult();
+
+    }
+
     public function add(Lexicon $entity, bool $flush = false): void
     {
         $this->getEntityManager()->persist($entity);