diff --git a/client/src/app/instance/search/components/result/datatable-actions.component.html b/client/src/app/instance/search/components/result/datatable-actions.component.html
index a1ff010a95fbcfa5304aadb79791f8841c341466..f0f888639fa2a7999bc3a511d93f5168aa64f902 100644
--- a/client/src/app/instance/search/components/result/datatable-actions.component.html
+++ b/client/src/app/instance/search/components/result/datatable-actions.component.html
@@ -18,15 +18,21 @@
                 <span class="fas fa-file"></span> VOtable
             </a>
         </li>
-        <li *ngIf="getConfigDownloadResultFormat('download_vo')" role="menuitem">
-            <a class="dropdown-item" (click)="broadcastVotable()">
+        <li *ngIf="getConfigDownloadResultFormat('download_vo')" role="menuitem" [class.disabled]="!sampRegistered">
+            <a class="dropdown-item" [class.disabled]="!sampRegistered" (click)="broadcastVotable()">
                 <span class="fas fa-broadcast-tower"></span> Broadcast VOtable
             </a>
         </li>
         <li *ngIf="getConfigDownloadResultFormat('download_archive')" role="menuitem">
-            <a class="dropdown-item" [href]="getUrlArchive()" (click)="click($event, getUrlArchive(), 'zip')">
+            <a class="dropdown-item" [href]="createFilesArchiveUrl()" (click)="createFilesArchive($event, createFilesArchiveUrl())">
                 <span class="fas fa-archive"></span> Download files archive
             </a>
         </li>
     </ul>
 </div>
+
+<div *ngIf="archiveInProgress">
+    <span class="fas fa-circle-notch fa-spin fa-3x"></span>
+    <span class="sr-only">Loading...</span>
+    Please wait archive is under construction...
+</div>
\ No newline at end of file
diff --git a/client/src/app/instance/search/components/result/datatable-actions.component.ts b/client/src/app/instance/search/components/result/datatable-actions.component.ts
index 5c29499606f57e2117b0fbec16fc780b7a23d630..cdb4287662b91488e51c949fbd3f2c4d60dbebf2 100644
--- a/client/src/app/instance/search/components/result/datatable-actions.component.ts
+++ b/client/src/app/instance/search/components/result/datatable-actions.component.ts
@@ -1,5 +1,6 @@
 import { Component, Input, Output, EventEmitter } from '@angular/core';
 import { HttpClient } from '@angular/common/http';
+import { interval, Subscription} from 'rxjs';
 
 import { ToastrService } from 'ngx-toastr';
 
@@ -23,6 +24,12 @@ export class DatatableActionsComponent {
     @Input() dataLength: number;
     @Input() sampRegistered: boolean;
     @Output() broadcast: EventEmitter<string> = new EventEmitter();
+    @Output() startsDownloadingFile: EventEmitter<{url: string, filename: string}> = new EventEmitter();
+
+    archiveName = '';
+    archiveId ='';
+    archiveInProgress = false;
+    archiveIsAvailableSubscription: Subscription
 
     constructor(private appConfig: AppConfigService, private http: HttpClient, private toastr: ToastrService) { }
 
@@ -68,15 +75,27 @@ export class DatatableActionsComponent {
         return `${attributeId.id}::in::${this.selectedData.join('|')}`;
     }
 
+    /**
+     * Allows to download file.
+     */
+    click(event, href, extension): void {
+        event.preventDefault();
+
+        const url = href;
+        const filename = `${this.datasetSelected}.${extension}`;
+
+        this.startsDownloadingFile.emit({ url, filename });
+    }
+
     /**
      * Returns URL to download archive.
      *
      * @return boolean
      */
-    getUrlArchive(): string {
-        let query: string = `${getHost(this.appConfig.apiUrl)}/archive/${this.datasetSelected}?a=${this.outputList.join(';')}`;
+    createFilesArchiveUrl(): string {
+        let query: string = `${getHost(this.appConfig.apiUrl)}/start-task-create-archive/${this.datasetSelected}?a=${this.outputList.join(';')}`;
         if (this.criteriaList.length > 0) {
-            query += `&c=${this.criteriaList.map(criterion => criterionToString(criterion)).join(';')};${this.getCriterionSelectedData()}`;
+            query += `&c=${this.criteriaList.map(criterion => criterionToString(criterion)).join(';')}`;
         } else {
             query += `&c=${this.getCriterionSelectedData()}`;
         }
@@ -86,6 +105,36 @@ export class DatatableActionsComponent {
         return query;
     }
 
+    getArchiveUrl() {
+        return `${getHost(this.appConfig.apiUrl)}/download-archive/${this.datasetSelected}/${this.archiveId}`;
+    }
+
+    testArchiveIsAvailable() {
+        const url = `${getHost(this.appConfig.apiUrl)}/is-archive-available/${this.archiveId}`;
+        this.http.get<{"archive_is_available": boolean}>(url).subscribe(data => {
+            console.log(data);
+            if (data.archive_is_available) {
+                this.archiveInProgress = false;
+                this.archiveIsAvailableSubscription.unsubscribe();
+                this.startsDownloadingFile.emit({ url: this.getArchiveUrl(), filename: this.archiveName })
+            }
+        });
+    }
+
+    /**
+     * Starts the creation of the files archive
+     */
+    createFilesArchive(event, href): void {
+        event.preventDefault();
+
+        this.http.get<{"archive_name": string, "archive_id": string}>(href).subscribe(data => {
+            this.archiveInProgress = true;
+            this.archiveName = data.archive_name;
+            this.archiveId = data.archive_id;
+            this.archiveIsAvailableSubscription = interval(1000).subscribe(() => this.testArchiveIsAvailable());
+        });
+    }
+
     /**
      * Emits event to  action to broadcast data.
      *
@@ -95,23 +144,7 @@ export class DatatableActionsComponent {
         this.broadcast.emit(this.getUrl('votable'));
     }
 
-    /**
-     * Allows to download file.
-     */
-    click(event, href, extension): void {
-        event.preventDefault();
-
-        if (extension === 'zip') {
-            this.toastr.info('Achive is under construction, please wait', 'Download archive');
-        }
-
-        this.http.get(href, {responseType: "blob"}).subscribe(
-            data => {
-                let downloadLink = document.createElement('a');
-                downloadLink.href = window.URL.createObjectURL(data);
-                downloadLink.setAttribute('download', `${this.datasetSelected}.${extension}`);
-                downloadLink.click();
-            }
-        );
+    ngOnDestroy() {
+        this.archiveIsAvailableSubscription.unsubscribe();
     }
 }
diff --git a/client/src/app/instance/search/components/result/datatable-tab.component.html b/client/src/app/instance/search/components/result/datatable-tab.component.html
index c638c569a6788c2fcad9652d1aa1ee2d7b1c1439..e4b9620c5d80032da48676ddee61df2e5241e275 100644
--- a/client/src/app/instance/search/components/result/datatable-tab.component.html
+++ b/client/src/app/instance/search/components/result/datatable-tab.component.html
@@ -18,23 +18,24 @@
             [coneSearch]="coneSearch"
             [dataLength]="dataLength"
             [sampRegistered]="sampRegistered"
-            (broadcast)="broadcast.emit($event)">
+            (broadcast)="broadcast.emit($event)"
+            (startsDownloadingFile)="startsDownloadingFile.emit($event)">
         </app-datatable-actions>
         <app-datatable
-                [dataset]="datasetList | datasetByName:datasetSelected"
-                [instance]="instance"
-                [attributeList]="attributeList"
-                [outputList]="outputList"
-                [queryParams]="queryParams"
-                [dataLength]="dataLength"
-                [data]="data"
-                [dataIsLoading]="dataIsLoading"
-                [dataIsLoaded]="dataIsLoaded"
-                [selectedData]="selectedData"
-                (retrieveData)="retrieveData.emit($event)"
-                (addSelectedData)="addSelectedData.emit($event)"
-                (deleteSelectedData)="deleteSelectedData.emit($event)"
-                (startsDownloadingFile)="startsDownloadingFile.emit($event)">
+            [dataset]="datasetList | datasetByName:datasetSelected"
+            [instance]="instance"
+            [attributeList]="attributeList"
+            [outputList]="outputList"
+            [queryParams]="queryParams"
+            [dataLength]="dataLength"
+            [data]="data"
+            [dataIsLoading]="dataIsLoading"
+            [dataIsLoaded]="dataIsLoaded"
+            [selectedData]="selectedData"
+            (retrieveData)="retrieveData.emit($event)"
+            (addSelectedData)="addSelectedData.emit($event)"
+            (deleteSelectedData)="deleteSelectedData.emit($event)"
+            (startsDownloadingFile)="startsDownloadingFile.emit($event)">
         </app-datatable>
     </accordion-group>
 </accordion>
diff --git a/client/src/app/instance/search/components/result/download-file-tab.component.html b/client/src/app/instance/search/components/result/download-file-tab.component.html
index 2030ad73e5a57d05676fc9ced77a03b14cecfe99..b47e6be34f1b9ca1b2044e225f820a7c89fb6cfa 100644
--- a/client/src/app/instance/search/components/result/download-file-tab.component.html
+++ b/client/src/app/instance/search/components/result/download-file-tab.component.html
@@ -4,7 +4,7 @@
         <ul>
             <li *ngFor="let downloadFile of downloadedFiles">
                 {{ downloadFile.name }} : 
-                <progressbar [value]="downloadFile.progress" type="warning" [striped]="false">{{ downloadFile.progress }}%</progressbar> 
+                <progressbar [value]="downloadFile.progress" [type]="getType(downloadFile.progress)" [animate]="true">{{ downloadFile.progress }}%</progressbar> 
             </li>
         </ul>
     </div>
diff --git a/client/src/app/instance/search/components/result/download-file-tab.component.ts b/client/src/app/instance/search/components/result/download-file-tab.component.ts
index cc8ad76cea0da902fd115c06c7159e8a626bb6ed..95d1e5b6389f9ef6b91263070574821c752901d9 100644
--- a/client/src/app/instance/search/components/result/download-file-tab.component.ts
+++ b/client/src/app/instance/search/components/result/download-file-tab.component.ts
@@ -22,4 +22,12 @@ import { DownloadFile } from 'src/app/instance/store/models';
 })
 export class DownloadFileTabComponent {
     @Input() downloadedFiles: DownloadFile[];
+
+    getType(value: number): 'success' | 'info' {
+        if (value < 100) {
+            return 'info';
+        }
+        
+        return 'success';
+    }
 }
diff --git a/client/src/app/instance/search/components/result/download.component.spec.ts b/client/src/app/instance/search/components/result/download.component.spec.ts
index 840d91af39bb8e863a90a42c9dbc9792085a52b8..d2129d21d79ea90cfc4d7781ca853cdb9556729e 100644
--- a/client/src/app/instance/search/components/result/download.component.spec.ts
+++ b/client/src/app/instance/search/components/result/download.component.spec.ts
@@ -395,7 +395,7 @@ describe('[Instance][Search][Component][Result] DownloadComponent', () => {
         expect(component.getUrl('csv')).toBe('http://test.com/search/myDataset?a=1;2;3&c=1::eq::one;2::eq::two&cs=4:5:6&f=csv');
     });
 
-    it('#getUrlArchive() should construct url to access to archive', () => {
+    it('#getArchiveUrl() should construct url to access to archive', () => {
         appConfigServiceStub.apiUrl = 'http://test.com';
         component.datasetSelected = 'myDataset';
         component.outputList = [1, 2, 3];
@@ -404,7 +404,7 @@ describe('[Instance][Search][Component][Result] DownloadComponent', () => {
             {'id':2,'type':'field','operator':'eq','value':'two'} as FieldCriterion
         ];
         component.coneSearch = { ra: 4, dec: 5, radius: 6 };
-        expect(component.getUrlArchive()).toBe('http://test.com/archive/myDataset?a=1;2;3&c=1::eq::one;2::eq::two&cs=4:5:6');
+        expect(component.getArchiveUrl()).toBe('http://test.com/archive/myDataset?a=1;2;3&c=1::eq::one;2::eq::two&cs=4:5:6');
     });
 
     it('#broadcastVotable() should raise broadcast event when clicked', () => {
diff --git a/client/src/app/instance/search/components/result/download.component.ts b/client/src/app/instance/search/components/result/download.component.ts
index 9a8f21ad7ffe148d176fc41a08cdc4efca1b1a10..95bd94a066f4616691ba5036aeac21c9046ba3c9 100644
--- a/client/src/app/instance/search/components/result/download.component.ts
+++ b/client/src/app/instance/search/components/result/download.component.ts
@@ -102,7 +102,7 @@ export class DownloadComponent implements OnDestroy {
         const url = href;
         const filename = `${this.datasetSelected}.${extension}`;
 
-        this.startsDownloadingFile.emit({ url, filename })
+        this.startsDownloadingFile.emit({ url, filename });
     }
 
     /**
@@ -120,7 +120,7 @@ export class DownloadComponent implements OnDestroy {
      * @return boolean
      */
     createFilesArchiveUrl(): string {
-        let query: string = `${getHost(this.appConfig.apiUrl)}/archive/${this.datasetSelected}?a=${this.outputList.join(';')}`;
+        let query: string = `${getHost(this.appConfig.apiUrl)}/start-task-create-archive/${this.datasetSelected}?a=${this.outputList.join(';')}`;
         if (this.criteriaList.length > 0) {
             query += `&c=${this.criteriaList.map(criterion => criterionToString(criterion)).join(';')}`;
         }
@@ -131,11 +131,11 @@ export class DownloadComponent implements OnDestroy {
     }
 
     getArchiveUrl() {
-        return `${getHost(this.appConfig.apiUrl)}/download-archive/${this.datasetSelected}?archive_id=${this.archiveId}`;
+        return `${getHost(this.appConfig.apiUrl)}/download-archive/${this.datasetSelected}/${this.archiveId}`;
     }
 
     testArchiveIsAvailable() {
-        const url = `${getHost(this.appConfig.apiUrl)}/archive-is-available?archive_id=${this.archiveId}`;
+        const url = `${getHost(this.appConfig.apiUrl)}/is-archive-available/${this.archiveId}`;
         this.http.get<{"archive_is_available": boolean}>(url).subscribe(data => {
             if (data.archive_is_available) {
                 this.archiveInProgress = false;
diff --git a/server/app/dependencies.php b/server/app/dependencies.php
index d96c1080ef3139588c55d3c3b521a835ea605a5f..c8d86647e3a01033a1a103d15181b68dc6a72539 100644
--- a/server/app/dependencies.php
+++ b/server/app/dependencies.php
@@ -211,12 +211,24 @@ $container->set('App\Action\SearchAction', function (ContainerInterface $c) {
     );
 });
 
-$container->set('App\Action\ArchiveAction', function (ContainerInterface $c) {
-    return new App\Action\ArchiveAction($c->get('em'), $c->get('rmq'), $c->get(SETTINGS)['token']);
+$container->set('App\Action\StartTaskCreateResultAction', function (ContainerInterface $c) {
+    return new App\Action\StartTaskCreateResultAction($c->get('em'), $c->get('rmq'), $c->get(SETTINGS)['token']);
 });
 
-$container->set('App\Action\ArchiveIsAvailableAction', function (ContainerInterface $c) {
-    return new App\Action\ArchiveIsAvailableAction($c->get('em'), $c->get('settings')['data_path'], $c->get(SETTINGS)['token']);
+$container->set('App\Action\IsResultAvailableAction', function (ContainerInterface $c) {
+    return new App\Action\IsResultAvailableAction($c->get('em'), $c->get('settings')['data_path'], $c->get(SETTINGS)['token']);
+});
+
+$container->set('App\Action\DownloadResultAction', function (ContainerInterface $c) {
+    return new App\Action\DownloadResultAction($c->get('em'), $c->get('settings')['data_path'], $c->get(SETTINGS)['token']);
+});
+
+$container->set('App\Action\StartTaskCreateArchiveAction', function (ContainerInterface $c) {
+    return new App\Action\StartTaskCreateArchiveAction($c->get('em'), $c->get('rmq'), $c->get(SETTINGS)['token']);
+});
+
+$container->set('App\Action\IsArchiveAvailableAction', function (ContainerInterface $c) {
+    return new App\Action\IsArchiveAvailableAction($c->get('em'), $c->get('settings')['data_path'], $c->get(SETTINGS)['token']);
 });
 
 $container->set('App\Action\DownloadArchiveAction', function (ContainerInterface $c) {
diff --git a/server/app/routes.php b/server/app/routes.php
index 634a35997b6a3b2f32f1650b343747e7414c8f62..a8aa5536e8b9fdb2cbf044ff00082091a3b224e0 100644
--- a/server/app/routes.php
+++ b/server/app/routes.php
@@ -15,6 +15,7 @@ use Slim\Routing\RouteCollectorProxy;
 $app->get('/', App\Action\RootAction::class);
 $app->get('/client-settings', App\Action\ClientSettingsAction::class);
 
+// Metamodel actions
 $app->group('', function (RouteCollectorProxy $group) {
     $group->map([OPTIONS, GET, POST], '/select', App\Action\SelectListAction::class);
     $group->map([OPTIONS, GET, PUT, DELETE], '/select/{name}', App\Action\SelectAction::class);
@@ -30,6 +31,7 @@ $app->group('', function (RouteCollectorProxy $group) {
     explode(',', $container->get(SETTINGS)['token']['admin_roles'])
 ));
 
+// Metamodel actions
 $app->group('', function (RouteCollectorProxy $group) {
     $group->map([OPTIONS, GET, POST], '/survey', App\Action\SurveyListAction::class);
     $group->map([OPTIONS, GET, PUT, DELETE], '/survey/{name}', App\Action\SurveyAction::class);
@@ -67,10 +69,19 @@ $app->group('', function (RouteCollectorProxy $group) {
     explode(',', $container->get(SETTINGS)['token']['admin_roles'])
 ));
 
+// Search actions
 $app->get('/search/{dname}', App\Action\SearchAction::class);
-$app->get('/archive/{dname}', App\Action\ArchiveAction::class);
-$app->get('/archive-is-available', App\Action\ArchiveIsAvailableAction::class);
-$app->get('/download-archive/{dname}', App\Action\DownloadArchiveAction::class);
+
+$app->get('/start-task-create-result/{dname}', App\Action\StartTaskCreateResultAction::class);
+$app->get('/is-result-available/{id}', App\Action\IsResultAvailableAction::class);
+$app->get('/download-result/{dname}/{id}', App\Action\DownloadResultAction::class);
+
+// Archive actions
+$app->get('/start-task-create-archive/{dname}', App\Action\StartTaskCreateArchiveAction::class);
+$app->get('/is-archive-available/{id}', App\Action\IsArchiveAvailableAction::class);
+$app->get('/download-archive/{dname}/{id}', App\Action\DownloadArchiveAction::class);
+
+// Explore and download individual files
 $app->get('/dataset-file-explorer/{dname}[{fpath:.*}]', App\Action\DatasetFileExplorerAction::class);
 $app->get('/download-instance-file/{iname}/[{fpath:.*}]', App\Action\DownloadInstanceFileAction::class);
 $app->get('/download-file/{dname}/[{fpath:.*}]', App\Action\DownloadFileAction::class);
diff --git a/server/src/Action/DownloadArchiveAction.php b/server/src/Action/DownloadArchiveAction.php
index 13ce380bcdf245777d6eecbe540a59565c21ee8d..f01c876943892f3e99c5104317a946a0c9debbf0 100644
--- a/server/src/Action/DownloadArchiveAction.php
+++ b/server/src/Action/DownloadArchiveAction.php
@@ -87,10 +87,8 @@ final class DownloadArchiveAction extends AbstractAction
             );
         }
         
-        $queryParams = $request->getQueryParams();
-        $archiveId = $queryParams['archive_id'];
-
         // Search the file
+        $archiveId = $args['id'];
         $filePath = $this->dataPath . '/ARCHIVE/' . $archiveId . '.zip';
 
         // If the file not found 404
diff --git a/server/src/Action/DownloadResultAction.php b/server/src/Action/DownloadResultAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..298608715c693789a24f649dfa5343a4ed4bccf7
--- /dev/null
+++ b/server/src/Action/DownloadResultAction.php
@@ -0,0 +1,111 @@
+<?php
+
+/*
+ * This file is part of Anis Server.
+ *
+ * (c) Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+declare(strict_types=1);
+
+namespace App\Action;
+
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Message\ResponseInterface as Response;
+use Doctrine\ORM\EntityManagerInterface;
+use Slim\Exception\HttpNotFoundException;
+use Nyholm\Psr7\Factory\Psr17Factory;
+
+/**
+ * @author François Agneray <francois.agneray@lam.fr>
+ * @package App\Action
+ */
+final class DownloadResultAction extends AbstractAction
+{
+    /**
+     * Contains anis-server data path
+     *
+     * @var string
+     */
+    private $dataPath;
+
+    /**
+     * Contains settings to handle Json Web Token
+     *
+     * @var array
+     */
+    private $settings;
+
+    /**
+     * Create the classe before call __invoke to execute the action
+     *
+     * @param EntityManagerInterface $em       Doctrine Entity Manager Interface
+     * @param string                 $dataPath Contains anis-server data path
+     * @param array                  $settings Settings about token
+     */
+    public function __construct(EntityManagerInterface $em, string $dataPath, array $settings)
+    {
+        parent::__construct($em);
+        $this->dataPath = $dataPath;
+        $this->settings = $settings;
+    }
+
+    /**
+     * `GET` Returns the file found
+     *
+     * @param  ServerRequestInterface $request  PSR-7 This object represents the HTTP request
+     * @param  ResponseInterface      $response PSR-7 This object represents the HTTP response
+     * @param  string[]               $args     This table contains information transmitted in the URL (see routes.php)
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(Request $request, Response $response, array $args): Response
+    {
+        if ($request->getMethod() === OPTIONS) {
+            return $response->withHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
+        }
+
+        // Search the correct dataset with primary key
+        $dataset = $this->em->find('App\Entity\Dataset', $args['dname']);
+
+        // If dataset is not found 404
+        if (is_null($dataset)) {
+            throw new HttpNotFoundException(
+                $request,
+                'Dataset with name ' . $args['dname'] . ' is not found'
+            );
+        }
+
+        // If dataset is private and authorization enabled
+        if (!$dataset->getPublic() && boolval($this->settings['enabled'])) {
+            $this->verifyDatasetAuthorization(
+                $request,
+                $dataset->getName(),
+                explode(',', $this->settings['admin_roles'])
+            );
+        }
+        
+        // Search the file
+        $fileId = $args['id'];
+        $filePath = $this->dataPath . '/RESULT/' . $fileId;
+
+        // If the file not found 404
+        if (!file_exists($filePath)) {
+            throw new HttpNotFoundException(
+                $request,
+                'Result file with name ' . $fileId . ' is not found'
+            );
+        }
+
+        // If the file found so stream it
+        $psr17Factory = new Psr17Factory();
+        $stream = $psr17Factory->createStreamFromFile($filePath, 'r');
+
+        return $response->withBody($stream)
+            ->withHeader('Content-Disposition', 'attachment; filename=' . basename($filePath) . ';')
+            ->withHeader('Content-Type', mime_content_type($filePath))
+            ->withHeader('Content-Length', filesize($filePath));
+    }
+}
diff --git a/server/src/Action/ArchiveIsAvailableAction.php b/server/src/Action/IsArchiveAvailableAction.php
similarity index 90%
rename from server/src/Action/ArchiveIsAvailableAction.php
rename to server/src/Action/IsArchiveAvailableAction.php
index 81219d4b3852af6089eba0559b6d829d4984aa98..3548088c620b319af7956eeccf0f52855983ccd3 100644
--- a/server/src/Action/ArchiveIsAvailableAction.php
+++ b/server/src/Action/IsArchiveAvailableAction.php
@@ -22,7 +22,7 @@ use Nyholm\Psr7\Factory\Psr17Factory;
  * @author François Agneray <francois.agneray@lam.fr>
  * @package App\Action
  */
-final class ArchiveIsAvailableAction extends AbstractAction
+final class IsArchiveAvailableAction extends AbstractAction
 {
     /**
      * Contains anis-server data path
@@ -67,11 +67,10 @@ final class ArchiveIsAvailableAction extends AbstractAction
             return $response->withHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
         }
         
-        $queryParams = $request->getQueryParams();
-        $archiveId = $queryParams['archive_id'] . '.zip';
+        $archiveId = $args['id'];
 
         // Search the file
-        $filePath = $this->dataPath . '/ARCHIVE/' . $archiveId;
+        $filePath = $this->dataPath . '/ARCHIVE/' . $archiveId . '.zip';
 
         $isAvailable = false;
         if (file_exists($filePath)) {
diff --git a/server/src/Action/IsResultAvailableAction.php b/server/src/Action/IsResultAvailableAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..fa612318a4977c4d9a180412ed3c0fc7cc6151f2
--- /dev/null
+++ b/server/src/Action/IsResultAvailableAction.php
@@ -0,0 +1,84 @@
+<?php
+
+/*
+ * This file is part of Anis Server.
+ *
+ * (c) Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+declare(strict_types=1);
+
+namespace App\Action;
+
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Message\ResponseInterface as Response;
+use Doctrine\ORM\EntityManagerInterface;
+use Slim\Exception\HttpNotFoundException;
+use Nyholm\Psr7\Factory\Psr17Factory;
+
+/**
+ * @author François Agneray <francois.agneray@lam.fr>
+ * @package App\Action
+ */
+final class IsResultAvailableAction extends AbstractAction
+{
+    /**
+     * Contains anis-server data path
+     *
+     * @var string
+     */
+    private $dataPath;
+
+    /**
+     * Contains settings to handle Json Web Token
+     *
+     * @var array
+     */
+    private $settings;
+
+    /**
+     * Create the classe before call __invoke to execute the action
+     *
+     * @param EntityManagerInterface $em       Doctrine Entity Manager Interface
+     * @param string                 $dataPath Contains anis-server data path
+     * @param array                  $settings Settings about token
+     */
+    public function __construct(EntityManagerInterface $em, string $dataPath, array $settings)
+    {
+        parent::__construct($em);
+        $this->dataPath = $dataPath;
+        $this->settings = $settings;
+    }
+
+    /**
+     * `GET` Returns the file found
+     *
+     * @param  ServerRequestInterface $request  PSR-7 This object represents the HTTP request
+     * @param  ResponseInterface      $response PSR-7 This object represents the HTTP response
+     * @param  string[]               $args     This table contains information transmitted in the URL (see routes.php)
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(Request $request, Response $response, array $args): Response
+    {
+        if ($request->getMethod() === OPTIONS) {
+            return $response->withHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
+        }
+        
+        $fileId = $args['id'];
+
+        // Search the file
+        $filePath = $this->dataPath . '/RESULT/' . $fileId;
+
+        $isAvailable = false;
+        if (file_exists($filePath)) {
+            $isAvailable = true;
+        }
+
+        $payload = json_encode(array('file_is_available' => $isAvailable));
+        $response->getBody()->write($payload);
+        return $response;
+    }
+}
diff --git a/server/src/Action/ArchiveAction.php b/server/src/Action/StartTaskCreateArchiveAction.php
similarity index 98%
rename from server/src/Action/ArchiveAction.php
rename to server/src/Action/StartTaskCreateArchiveAction.php
index a6009f5ae15e072696726935b245731e54f883dc..898183d400cd1a63c400a7fc0a76ead00a46a5c2 100644
--- a/server/src/Action/ArchiveAction.php
+++ b/server/src/Action/StartTaskCreateArchiveAction.php
@@ -31,7 +31,7 @@ use PhpAmqpLib\Message\AMQPMessage;
  * @author François Agneray <francois.agneray@lam.fr>
  * @package App\Action
  */
-final class ArchiveAction extends AbstractAction
+final class StartTaskCreateArchiveAction extends AbstractAction
 {
     /**
      * Contains RabbitMQ connection socket
diff --git a/server/src/Action/StartTaskCreateResultAction.php b/server/src/Action/StartTaskCreateResultAction.php
new file mode 100644
index 0000000000000000000000000000000000000000..567ed6a1fde045e649c02e955e4c19401b72aac1
--- /dev/null
+++ b/server/src/Action/StartTaskCreateResultAction.php
@@ -0,0 +1,143 @@
+<?php
+
+/*
+ * This file is part of Anis Server.
+ *
+ * (c) Laboratoire d'Astrophysique de Marseille / CNRS
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+declare(strict_types=1);
+
+namespace App\Action;
+
+use Psr\Http\Message\ServerRequestInterface as Request;
+use Psr\Http\Message\ResponseInterface as Response;
+use Slim\Exception\HttpBadRequestException;
+use Slim\Exception\HttpNotFoundException;
+use Slim\Exception\HttpInternalServerErrorException;
+use Doctrine\ORM\EntityManagerInterface;
+use Nyholm\Psr7\Factory\Psr17Factory;
+use App\Search\DBALConnectionFactory;
+use App\Search\Query\AnisQueryBuilder;
+use App\Search\Response\IResponseFactory;
+use App\Search\SearchException;
+use PhpAmqpLib\Connection\AbstractConnection;
+use PhpAmqpLib\Connection\AMQPStreamConnection;
+use PhpAmqpLib\Message\AMQPMessage;
+
+/**
+ * @author François Agneray <francois.agneray@lam.fr>
+ * @package App\Action
+ */
+final class StartTaskCreateArchiveAction extends AbstractAction
+{
+    /**
+     * Contains RabbitMQ connection socket
+     * 
+     * @var AbstractConnection
+     */
+    private $rmq;
+
+    /**
+     * Contains settings to handle Json Web Token (app/settings.php)
+     *
+     * @var array
+     */
+    private $settings;
+
+    /**
+     * Create the classe before call __invoke to execute the action
+     *
+     * @param EntityManagerInterface $em       Doctrine Entity Manager Interface
+     * @param AbstractConnection     $rmq      RabbitMQ connection socket
+     * @param array                  $settings Settings about token
+     */
+    public function __construct(
+        EntityManagerInterface $em,
+        AbstractConnection $rmq,
+        array $settings
+    ) {
+        parent::__construct($em);
+        $this->rmq = $rmq;
+        $this->settings = $settings;
+    }
+
+    /**
+     * `GET` Starts an asynchronous task, through rabbitmq, to build an archive
+     *
+     * @param  ServerRequestInterface $request  PSR-7 This object represents the HTTP request
+     * @param  ResponseInterface      $response PSR-7 This object represents the HTTP response
+     * @param  string[]               $args     This table contains information transmitted in the URL (see routes.php)
+     *
+     * @return ResponseInterface
+     */
+    public function __invoke(Request $request, Response $response, array $args): Response
+    {
+        if ($request->getMethod() === OPTIONS) {
+            return $response->withHeader('Access-Control-Allow-Methods', 'GET, OPTIONS');
+        }
+
+        // Search the correct dataset with primary key
+        $datasetName = $args['dname'];
+        $dataset = $this->em->find('App\Entity\Dataset', $datasetName);
+
+        // If dataset is not found 404
+        if (is_null($dataset)) {
+            throw new HttpNotFoundException(
+                $request,
+                'Dataset with name ' . $datasetName . ' is not found'
+            );
+        }
+
+        // If dataset is private and authorization enabled
+        if (!$dataset->getPublic() && boolval($this->settings['enabled'])) {
+            $this->verifyDatasetAuthorization(
+                $request,
+                $dataset->getName(),
+                explode(',', $this->settings['admin_roles'])
+            );
+        }
+
+        $queryParams = $request->getQueryParams();
+
+        // The parameter "a" is mandatory
+        if (!array_key_exists('a', $queryParams)) {
+            throw new HttpBadRequestException(
+                $request,
+                'Param a is required for this request'
+            );
+        }
+
+        // Search extension
+        if ($queryParams === 'csv') {
+            $extension = '.csv';
+        } else if ($queryParams === 'ascii') {
+            $extension = '.txt';
+        } else if ($queryParams === 'votable') {
+            $extension = '.xml';
+        } else {
+            $extension = '.json';
+        }
+
+        // Create the name of the future archive
+        $fileName = 'result_' . $dataset->getName() . '_' . (new \DateTime())->format('Y-m-d\TH:i:s') . '.' . $extension;
+        $fileId = uniqid();
+
+        // Publish message in the archive queue
+        $channel = $this->rmq->channel();
+        $channel->queue_declare('archive', false, false, false, false);
+        $msg = new AMQPMessage(json_encode(array(
+            'file_id' => $fileId,
+            'dataset_name' => $datasetName,
+            'query' => $request->getUri()->getQuery()
+        )));
+        $channel->basic_publish($msg, '', 'result');
+
+        // Just returns the future archive name
+        $payload = json_encode(array('file_name' => $fileName, 'file_id' => $fileId));
+        $response->getBody()->write($payload);
+        return $response;
+    }
+}
diff --git a/tasks/src/anis_tasks/app.py b/tasks/src/anis_tasks/app.py
index 810e581cecd495254e71148f7545d5561383696b..5dcd1b275d1b211f412bc2350b1b630993ccc4e0 100644
--- a/tasks/src/anis_tasks/app.py
+++ b/tasks/src/anis_tasks/app.py
@@ -6,7 +6,7 @@ import pika
 from retry import retry
 
 # Local application imports
-from anis_tasks import utils, archive
+from anis_tasks import utils, archive, result
 
 @retry(pika.exceptions.AMQPConnectionError, delay=5, jitter=(1, 3))
 def run():
@@ -23,6 +23,10 @@ def run():
         channel.queue_declare(queue='archive')
         channel.basic_consume(queue='archive', on_message_callback=archive.archive_handler, auto_ack=True)
 
+        # Add result task handler
+        channel.queue_declare(queue='result')
+        channel.basic_consume(queue='result', on_message_callback=result.result_handler, auto_ack=True)
+
         # Start
         logging.info("ANIS tasks started")
         channel.start_consuming()
diff --git a/tasks/src/anis_tasks/archive.py b/tasks/src/anis_tasks/archive.py
index 1f799b7768a235e825ae54837092a019b0b8140a..d439f79e0e108ad01cfe592bd00883b49d9e52d4 100644
--- a/tasks/src/anis_tasks/archive.py
+++ b/tasks/src/anis_tasks/archive.py
@@ -25,7 +25,7 @@ def archive_handler(ch, method, properties, body):
     zip = ZipFile(zip_path + ".tmp", 'w')
 
     # Search files
-    for row in data:
+    for row in data.json():
         files_added = []
         for attribute in attributes_selected:
             attribute_label = attribute["label"]
diff --git a/tasks/src/anis_tasks/result.py b/tasks/src/anis_tasks/result.py
new file mode 100644
index 0000000000000000000000000000000000000000..1278e00da40e8abe90c844122e34ea58fe41deda
--- /dev/null
+++ b/tasks/src/anis_tasks/result.py
@@ -0,0 +1,31 @@
+# Standard library imports
+import logging, json, os
+from zipfile import ZipFile
+
+# Local application imports
+from anis_tasks import utils
+
+def result_handler(ch, method, properties, body):
+    logging.info("Processing a new result message")
+
+    # Decode JSON
+    message = json.loads(body)
+
+    # Retrieve data
+    data = utils.search_data(message["dataset_name"], message["query"])
+
+    # create a File object
+    data_path = utils.get_data_path()
+    file_path = data_path + "/RESULT/" + message["file_id"]
+    file = open(file_path + ".tmp", "w")
+
+    # Write data
+    file.write(data)
+
+    # close the File
+    file.close()
+
+    # Rename the tmp file with the correct filename (id)
+    os.rename(file_path + ".tmp", file_path)
+
+    logging.info("File created: " + file_path)
diff --git a/tasks/src/anis_tasks/utils.py b/tasks/src/anis_tasks/utils.py
index 738e6cce183e6f8705b60b6529676f5f15cae42e..689f4517620a1c630fe6bf0539bdd7c349df02ed 100644
--- a/tasks/src/anis_tasks/utils.py
+++ b/tasks/src/anis_tasks/utils.py
@@ -90,7 +90,7 @@ def search_data(dname, query):
     if (r.status_code == 500):
         raise AnisServerError(r.json()["message"])
 
-    return r.json()
+    return r
 
 class ConfigKeyNotFound(Exception):
     """