diff --git a/backend/src/main/java/fr/inra/urgi/gpds/api/brapi/v1/CallsController.java b/backend/src/main/java/fr/inra/urgi/gpds/api/brapi/v1/CallsController.java
index 433007fbf3356230dcfb4eb3af1c3935a639b4ba..9796212845c770a087eff1f25cfafb54faa097eb 100644
--- a/backend/src/main/java/fr/inra/urgi/gpds/api/brapi/v1/CallsController.java
+++ b/backend/src/main/java/fr/inra/urgi/gpds/api/brapi/v1/CallsController.java
@@ -1,7 +1,6 @@
 package fr.inra.urgi.gpds.api.brapi.v1;
 
-import com.google.common.collect.Lists;
-import com.google.common.reflect.ClassPath;
+import com.google.common.collect.ImmutableSet;
 import fr.inra.urgi.gpds.domain.brapi.v1.data.BrapiCall;
 import fr.inra.urgi.gpds.domain.brapi.v1.response.BrapiListResponse;
 import fr.inra.urgi.gpds.domain.criteria.base.PaginationCriteriaImpl;
@@ -9,15 +8,19 @@ import fr.inra.urgi.gpds.domain.data.CallVO;
 import fr.inra.urgi.gpds.domain.response.ApiResponseFactory;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
-import org.springframework.web.bind.annotation.*;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import springfox.documentation.service.ApiDescription;
+import springfox.documentation.service.Documentation;
+import springfox.documentation.spring.web.DocumentationCache;
+import springfox.documentation.spring.web.plugins.Docket;
 
 import javax.validation.Valid;
-import java.io.IOException;
-import java.lang.reflect.Method;
-import java.util.*;
-
-import static org.springframework.web.bind.annotation.RequestMethod.GET;
-import static org.springframework.web.bind.annotation.RequestMethod.POST;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 /**
  * @author gcornut
@@ -25,132 +28,81 @@ import static org.springframework.web.bind.annotation.RequestMethod.POST;
 @Api(tags = {"Breeding API"}, description = "BrAPI endpoint")
 @RestController
 public class CallsController {
+    private static final String BRAPI_PATH = "/brapi/v1/";
 
-    private static final List<String> DATA_TYPES = Arrays.asList(
+    public static final Set<String> DEFAULT_DATA_TYPES = ImmutableSet.of(
         "json"
     );
 
-    private static final List<String> BRAPI_VERSIONS = Arrays.asList(
+    public static final Set<String> DEFAULT_BRAPI_VERSIONS = ImmutableSet.of(
         "1.0",
         "1.1",
         "1.2"
     );
 
-    private final List<BrapiCall> implementedCalls;
+    private List<BrapiCall> implementedCalls;
+
+    private final DocumentationCache documentationCache;
 
-    public CallsController() {
-        this.implementedCalls = listImplementedCalls();
+    @Autowired
+    public CallsController(DocumentationCache documentationCache) {
+        this.documentationCache = documentationCache;
     }
 
     /**
      * @link https://github.com/plantbreeding/API/blob/master/Specification/Calls/Calls.md
      */
     @ApiOperation("List implemented Breeding API calls")
-    @GetMapping(value = {"/brapi/v1/calls", "/brapi/v1/"})
+    @GetMapping("/brapi/v1/calls")
     public BrapiListResponse<BrapiCall> calls(@Valid PaginationCriteriaImpl criteria) {
+        if (implementedCalls == null) {
+            implementedCalls = swaggerToBrapiCalls();
+        }
+
         return ApiResponseFactory.createSubListResponse(
             criteria.getPageSize(), criteria.getPage(), implementedCalls
         );
     }
 
     /**
-     * Generate {@link BrapiCall} by reflectively reading Spring REST
-     * annotations
+     * Get swagger API documentation and transform it to list of BrAPI calls
+     *
+     * This must be done after swagger has time to generate the API
+     * documentation and thus can't be done in this class constructor
      */
-    private List<BrapiCall> listImplementedCalls() {
-        Map<String, BrapiCall> calls = new HashMap<>();
-
-        Class<?> aClass = getClass();
-        ClassLoader classLoader = aClass.getClassLoader();
-        ClassPath classPath;
-        try {
-            classPath = ClassPath.from(classLoader);
-        } catch (IOException e) {
-            throw new RuntimeException(e);
-        }
-
-        String brapiControllerPackage = aClass.getPackage().getName();
-        Set<ClassPath.ClassInfo> controllerClasses = classPath.getTopLevelClasses(brapiControllerPackage);
-        for (ClassPath.ClassInfo controllerClassInfo : controllerClasses) {
-            Class<?> controllerClass = controllerClassInfo.load();
-            if (controllerClass.getAnnotation(RestController.class) == null) {
-                // Class is not a RestController
-                continue;
-            }
-
-            for (Method method : controllerClass.getMethods()) {
-                ApiOperation apiOperation = method.getAnnotation(ApiOperation.class);
-                if (apiOperation != null && apiOperation.hidden()) {
-                    // Rest call is hidden = ignore
-                    continue;
-                }
-
-                String[] paths = getCallPath(method);
-                if (paths == null) {
-                    // No rest path mapping => ignore
-                    continue;
-                }
-                for (String path : paths) {
-                    String[] pathSplit = path.split("/brapi/v1/");
-                    if (pathSplit.length != 2) {
-                        continue;
-                    }
-                    path = pathSplit[1];
-
-                    RequestMethod[] httpMethods = getCallMethods(method);
-                    List<String> httpMethodNames = Lists.newArrayList();
-                    for (RequestMethod httpMethod : httpMethods) {
-                        httpMethodNames.add(httpMethod.name());
-                    }
-
-                    BrapiCall call = calls.get(path);
-                    if (call == null) {
-                        call = new CallVO(path);
-                        calls.put(path, call);
-                    }
-                    call.getMethods().addAll(httpMethodNames);
-                    call.getDatatypes().addAll(DATA_TYPES);
-                    call.getVersions().addAll(BRAPI_VERSIONS);
-                }
-            }
-        }
-
-        ArrayList<BrapiCall> allCalls = new ArrayList<>(calls.values());
-        // Sort by call name
-        Collections.sort(allCalls, Comparator.comparing(BrapiCall::getCall));
-        return allCalls;
-    }
-
-    private String[] getCallPath(Method method) {
-        RequestMapping annotation = method.getAnnotation(RequestMapping.class);
-        if (annotation != null) {
-            return annotation.value();
-        }
-        GetMapping getAnnotation = method.getAnnotation(GetMapping.class);
-        if (getAnnotation != null) {
-            return getAnnotation.value();
-        }
-        PostMapping postAnnotation = method.getAnnotation(PostMapping.class);
-        if (postAnnotation != null) {
-            return postAnnotation.value();
-        }
-        return null;
-    }
-
-    private RequestMethod[] getCallMethods(Method method) {
-        RequestMapping annotation = method.getAnnotation(RequestMapping.class);
-        if (annotation != null) {
-            return annotation.method();
-        }
-        GetMapping getAnnotation = method.getAnnotation(GetMapping.class);
-        if (getAnnotation != null) {
-            return new RequestMethod[]{GET};
-        }
-        PostMapping postAnnotation = method.getAnnotation(PostMapping.class);
-        if (postAnnotation != null) {
-            return new RequestMethod[]{POST};
-        }
-        return null;
+    private List<BrapiCall> swaggerToBrapiCalls() {
+        Documentation apiDocumentation = this.documentationCache.documentationByGroup(Docket.DEFAULT_GROUP_NAME);
+
+        // Get all endpoints
+        return apiDocumentation.getApiListings().values().stream()
+            .flatMap(endpointListing -> endpointListing.getApis().stream())
+            // Only with BrAPI path
+            .filter(endpointDescription -> endpointDescription.getPath().startsWith(BRAPI_PATH))
+            // Group by endpoint path (ex: /brapi/v1/phenotype => [GET, POST, ...])
+            .collect(Collectors.groupingBy(ApiDescription::getPath))
+            .entrySet().stream()
+            // Convert to BrAPI call
+            .map(endpointGroup -> {
+                String path = endpointGroup.getKey();
+                List<ApiDescription> endpoints = endpointGroup.getValue();
+
+                // BrAPI call path should not include the base BrAPI path
+                CallVO call = new CallVO(path.replace(BRAPI_PATH, ""));
+
+                // List every endpoint for current path
+                Set<String> methods = endpoints.stream()
+                    // List all operations for each endpoint
+                    .flatMap(endpointDescription -> endpointDescription.getOperations().stream())
+                    // List all methods
+                    .map(operation -> operation.getMethod().toString())
+                    .collect(Collectors.toSet());
+                call.setMethods(methods);
+
+                return call;
+            })
+            // Sort by call name
+            .sorted(Comparator.comparing(CallVO::getCall))
+            .collect(Collectors.toList());
     }
 
 }
diff --git a/backend/src/main/java/fr/inra/urgi/gpds/domain/data/CallVO.java b/backend/src/main/java/fr/inra/urgi/gpds/domain/data/CallVO.java
index eb071205e4ebcd0febd915386843c67a3cef20d5..9fbb1a3ee162df076dcf74e80d66c7649dd73233 100644
--- a/backend/src/main/java/fr/inra/urgi/gpds/domain/data/CallVO.java
+++ b/backend/src/main/java/fr/inra/urgi/gpds/domain/data/CallVO.java
@@ -2,24 +2,23 @@ package fr.inra.urgi.gpds.domain.data;
 
 import fr.inra.urgi.gpds.domain.brapi.v1.data.BrapiCall;
 
-import java.util.HashSet;
 import java.util.Set;
 
+import static fr.inra.urgi.gpds.api.brapi.v1.CallsController.DEFAULT_BRAPI_VERSIONS;
+import static fr.inra.urgi.gpds.api.brapi.v1.CallsController.DEFAULT_DATA_TYPES;
+
 /**
  * @author gcornut
  */
 public class CallVO implements BrapiCall {
 
-    private String call;
-    private Set<String> datatypes;
+    private final String call;
+    private Set<String> datatypes = DEFAULT_DATA_TYPES;
+    private Set<String> versions = DEFAULT_BRAPI_VERSIONS;
     private Set<String> methods;
-    private Set<String> versions;
 
     public CallVO(String call) {
         this.call = call;
-        this.datatypes = new HashSet<>();
-        this.methods = new HashSet<>();
-        this.versions = new HashSet<>();
     }
 
     @Override
@@ -42,4 +41,15 @@ public class CallVO implements BrapiCall {
         return versions;
     }
 
+    public void setDatatypes(Set<String> datatypes) {
+        this.datatypes = datatypes;
+    }
+
+    public void setMethods(Set<String> methods) {
+        this.methods = methods;
+    }
+
+    public void setVersions(Set<String> versions) {
+        this.versions = versions;
+    }
 }
diff --git a/backend/src/test/java/fr/inra/urgi/gpds/api/brapi/v1/CallsControllerTest.java b/backend/src/test/java/fr/inra/urgi/gpds/api/brapi/v1/CallsControllerTest.java
index e31c71e1d8ab270a1d855244ad3a3cd1d8492d4c..9f7f1fc91ecd63b593afdc8cc6de530916242c65 100644
--- a/backend/src/test/java/fr/inra/urgi/gpds/api/brapi/v1/CallsControllerTest.java
+++ b/backend/src/test/java/fr/inra/urgi/gpds/api/brapi/v1/CallsControllerTest.java
@@ -3,7 +3,8 @@ package fr.inra.urgi.gpds.api.brapi.v1;
 import org.junit.jupiter.api.Test;
 import org.junit.jupiter.api.extension.ExtendWith;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
+import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
+import org.springframework.boot.test.context.SpringBootTest;
 import org.springframework.http.MediaType;
 import org.springframework.test.context.junit.jupiter.SpringExtension;
 import org.springframework.test.web.servlet.MockMvc;
@@ -18,7 +19,8 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.
  * @author gcornut
  */
 @ExtendWith(SpringExtension.class)
-@WebMvcTest(controllers = CallsController.class)
+@SpringBootTest
+@AutoConfigureMockMvc
 class CallsControllerTest {
 
     @Autowired