diff --git a/application/modules/api/controllers/UserController.php b/application/modules/api/controllers/UserController.php
index d67f3182243b44e4b37788969f621102d9f57994..7688562b97a07c4168fbdc4fc421386a10a68301 100644
--- a/application/modules/api/controllers/UserController.php
+++ b/application/modules/api/controllers/UserController.php
@@ -31,6 +31,7 @@ class Api_UserController extends ZendAfi_Controller_Action {
     $user = Class_Users::getIdentity();
     $this->_helper
       ->json(['account' => ['label' => $user->getNomAff(),
+                            'login' => $user->getLogin(),
                             'card' => ['id'=> $user->getIdabon(),
                                        'expire_at' => $user->getDateFin()]
               ]]);
@@ -38,7 +39,49 @@ class Api_UserController extends ZendAfi_Controller_Action {
 
 
   public function loansAction() {
-    $this->view->loans = (new Class_User_Cards(Class_Users::getIdentity()))->getLoans();
+    $this->view->loans = $this->_userCards()->getLoans();
+  }
+
+
+  public function holdsAction() {
+    $this->view->holds = $this->_userCards()->getHolds();
+  }
+
+
+  public function renewLoanAction() {
+    $cards = $this->_userCards();
+    $loan_id = $this->_getParam('id');
+
+    $status = $cards->renewLoan($loan_id);
+
+    if ($status['statut'] == false)
+      return $this->_helper->json(['status' => 'error',
+                                   'error' => $status['erreur']]);
+
+    $loan = $cards->getLoans()
+                  ->detect(function($loan) use ($loan_id)
+                           {
+                             return $loan->getId() == $loan_id;
+                           });
+
+    return $this->_helper->json(['status' => 'renewed',
+                                 'date_due' => $loan->getDateRetourISO8601()]);
+  }
+
+
+  public function cancelHoldAction() {
+    $status = $this->_userCards()
+                   ->cancelHold($this->_getParam('id'));
+
+    return ($status['statut'] == false)
+      ? $this->_helper->json(['status' => 'error',
+                              'error' => $status['erreur']])
+      : $this->_helper->json(['status' => 'canceled']);
+  }
+
+
+  protected function _userCards() {
+    return new Class_User_Cards(Class_Users::getIdentity());
   }
 
 
diff --git a/application/modules/api/views/scripts/user/holds.pjson b/application/modules/api/views/scripts/user/holds.pjson
new file mode 100644
index 0000000000000000000000000000000000000000..87732946fb1170d8d50fbf7a5b3c62d234ebddb1
--- /dev/null
+++ b/application/modules/api/views/scripts/user/holds.pjson
@@ -0,0 +1,3 @@
+{
+	"holds": <?php echo $this->holds($this->holds) ?>
+}
diff --git a/library/Class/WebService/SIGB/Emprunt.php b/library/Class/WebService/SIGB/Emprunt.php
index e946729ea042e1c9c401322e220b669e0256df79..05901c3cb2d5d063c4933979de7491adcb10d9e3 100644
--- a/library/Class/WebService/SIGB/Emprunt.php
+++ b/library/Class/WebService/SIGB/Emprunt.php
@@ -32,6 +32,11 @@ class Class_WebService_SIGB_Emprunt extends Class_WebService_SIGB_ExemplaireOper
   }
 
 
+  public function getDateRetourISO8601() {
+    return implode('-', array_reverse(explode('/', $this->getDateRetour())));
+  }
+
+
   /**
    * @param string $retour
    * @return Class_WebService_SIGB_Emprunt
diff --git a/library/ZendAfi/View/Helper/Api/Holds.php b/library/ZendAfi/View/Helper/Api/Holds.php
new file mode 100644
index 0000000000000000000000000000000000000000..ddafc3d948cd3f7122b1fbee0c5d5b1b9f8a2b43
--- /dev/null
+++ b/library/ZendAfi/View/Helper/Api/Holds.php
@@ -0,0 +1,51 @@
+<?php
+/**
+ * Copyright (c) 2012-2014, Agence Française Informatique (AFI). All rights reserved.
+ *
+ * BOKEH is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU AFFERO GENERAL PUBLIC LICENSE as published by
+ * the Free Software Foundation.
+ *
+ * There are special exceptions to the terms and conditions of the AGPL as it
+ * is applied to this software (see README file).
+ *
+ * BOKEH is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU AFFERO GENERAL PUBLIC LICENSE for more details.
+ *
+ * You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE
+ * along with BOKEH; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
+ */
+
+
+class ZendAfi_View_Helper_Api_Holds extends Zend_View_Helper_Abstract {
+  public function holds($holds) {
+    return json_encode(
+                       $holds->collect([$this, 'holdToArray'])
+                       ->getArrayCopy()
+    );
+  }
+
+
+  public function holdToArray($hold) {
+    $datas = [
+              'id' => $hold->getId(),
+              'title' => $hold->getTitre(),
+              'author' => $hold->getAuteur(),
+              'status' => $hold->getEtat(),
+              'held_by' => $hold->getUserFullName(),
+              'library' => $hold->getBibliotheque() ];
+
+    if (!$record = $hold->getNoticeOPAC())
+      return $datas;
+
+    $datas['record'] = ['id' => $record->getId()];
+    if ($record->hasVignette())
+      $datas['record']['thumbnail'] = $record->getUrlVignette();
+
+    return $datas;
+  }
+}
+?>
\ No newline at end of file
diff --git a/library/ZendAfi/View/Helper/Api/Loans.php b/library/ZendAfi/View/Helper/Api/Loans.php
index c4542a247d7c893166d2905a249ba9d1b61b44d3..d90cedf859b652827378b89951947af53c278167 100644
--- a/library/ZendAfi/View/Helper/Api/Loans.php
+++ b/library/ZendAfi/View/Helper/Api/Loans.php
@@ -30,13 +30,22 @@ class ZendAfi_View_Helper_Api_Loans extends Zend_View_Helper_Abstract {
 
 
   public function loanToArray($loan) {
-    return [
-            'title' => $loan->getTitre(),
-            'author' => $loan->getAuteur(),
-            'date_due' => implode('-', array_reverse(explode('/', $loan->getDateRetour()))),
-            'loaned_by' => $loan->getUserFullName(),
-            'library' => $loan->getBibliotheque()
-    ];
+    $datas = [
+              'id' => $loan->getId(),
+              'title' => $loan->getTitre(),
+              'author' => $loan->getAuteur(),
+              'date_due' => $loan->getDateRetourISO8601(),
+              'loaned_by' => $loan->getUserFullName(),
+              'library' => $loan->getBibliotheque() ];
+
+    if (!$record = $loan->getNoticeOPAC())
+      return $datas;
+
+    $datas['record'] = ['id' => $record->getId()];
+    if ($record->hasVignette())
+      $datas['record']['thumbnail'] = $record->getUrlVignette();
+
+    return $datas;
   }
 }
 ?>
\ No newline at end of file
diff --git a/tests/application/modules/AbstractControllerTestCase.php b/tests/application/modules/AbstractControllerTestCase.php
index aca406855712afce0e1b929e58348b34794a4b34..6ad5af88956c096a4c4c5bd58e4a3a730b2c5fc6 100644
--- a/tests/application/modules/AbstractControllerTestCase.php
+++ b/tests/application/modules/AbstractControllerTestCase.php
@@ -197,6 +197,7 @@ abstract class AbstractControllerTestCase extends Zend_Test_PHPUnit_ControllerTe
     Class_WebService_BibNumerique_Vignette::resetInstance();
     Class_FileManager::reset();
     Class_Notice_Xsl::reset();
+    Class_CommSigb::setInstance(null);
   }
 
 
diff --git a/tests/scenarios/MobileApplication/UserAccountTest.php b/tests/scenarios/MobileApplication/UserAccountTest.php
index 1106b77ecc80507ab00c6787b1d1673f40d79b1d..935ef9517a35a14cc70864501c4d5ad257b0f684 100644
--- a/tests/scenarios/MobileApplication/UserAccountTest.php
+++ b/tests/scenarios/MobileApplication/UserAccountTest.php
@@ -20,13 +20,17 @@
  */
 abstract class Scenario_MobileApplication_UserAccountTestCase extends AbstractControllerTestCase {
   protected
-    $_storm_default_to_volatile = true;
+    $_storm_default_to_volatile = true,
+    $_potter,
+    $_sigb;
 
   public function setUp() {
     parent::setUp();
 
     $_SERVER['HTTPS'] = 'on';
 
+    Class_CommSigb::setInstance($this->_sigb = $this->mock());
+
     $puppy = $this->fixture('Class_Users',
                             ['id' => 345,
                              'pseudo' => 'Puppy',
@@ -43,24 +47,40 @@ abstract class Scenario_MobileApplication_UserAccountTestCase extends AbstractCo
                     'client_id' => 'My mobile app',
                     'user' => $puppy]);
 
-    $potter = new Class_WebService_SIGB_Emprunt('12', new Class_WebService_SIGB_Exemplaire(123));
-    $potter
+    $this->_potter = new Class_WebService_SIGB_Emprunt('12', new Class_WebService_SIGB_Exemplaire(123));
+    $this->_potter
       ->setDateRetour('01/01/1974')
-      ->setAuteur('J.K.R')
       ->setBibliotheque('Annecy')
-      ->getExemplaire()->setTitre('Potter');
+      ->getExemplaire()
+      ->setNoticeOPAC($this->fixture('Class_Notice',
+                                     ['id' => 34,
+                                      'url_vignette' => 'http://img.com/potter.jpg',
+                                      'titre_principal' => 'Potter',
+                                      'auteur_principal' => 'J.K.R' ]));
 
     $alice = new Class_WebService_SIGB_Emprunt('13', new Class_WebService_SIGB_Exemplaire(456));
     $alice
       ->setDateRetour(date('d/m/Y', strtotime('tomorrow')))
       ->getExemplaire()->setTitre('Alice');
 
-    $emprunteur = (new Class_WebService_SIGB_Emprunteur(345, 'puppy'))
-      ->empruntsAddAll([$potter, $alice]);
-
-    $puppy->setFicheSIGB(['fiche' => $emprunteur]);
-    $puppy->assertSave();
 
+    $afrodeezia = new Class_WebService_SIGB_Reservation('18', new Class_WebService_SIGB_Exemplaire(938));
+    $afrodeezia
+            ->setBibliotheque('Annecy')
+            ->setEtat('En attente')
+            ->getExemplaire()
+            ->setNoticeOPAC($this->fixture('Class_Notice',
+                                           ['id' => 83,
+                                            'url_vignette' => 'http://img.com/marcus.jpg',
+                                            'titre_principal' => 'Afrodeezia',
+                                            'auteur_principal' => 'Marcus Miller' ]));
+
+    $puppy
+      ->setFicheSigb(['fiche' =>
+                      (new Class_WebService_SIGB_Emprunteur(345, 'puppy'))
+                      ->empruntsAddAll([$this->_potter, $alice])
+                      ->reservationsAddAll([$afrodeezia])])
+      ->assertSave();
 
     ZendAfi_Auth::getInstance()->clearIdentity();
   }
@@ -93,11 +113,14 @@ class Scenario_MobileApplication_UserAccountLoansWithTokenTest extends Scenario_
 
   /** @test */
   public function responseShouldContainsPotterLoan() {
-    $this->assertEquals(['title' => 'Potter',
+    $this->assertEquals(['id' => '345_12',
+                         'title' => 'Potter',
                          'author' => 'J.K.R',
                          'date_due' => '1974-01-01',
                          'loaned_by' => 'puppy',
-                         'library' => 'Annecy'
+                         'library' => 'Annecy',
+                         'record' => [ 'id' => '34',
+                                       'thumbnail' => 'http://img.com/potter.jpg' ]
                          ],
                         $this->_json['loans'][0]);
   }
@@ -120,6 +143,61 @@ class Scenario_MobileApplication_UserAccountLoansWithTokenTest extends Scenario_
 
 
 
+class Scenario_MobileApplication_UserAccountRenewTest extends Scenario_MobileApplication_UserAccountTestCase {
+  /** @test */
+  public function resultShouldAnswerSuccess() {
+    $this->_sigb->whenCalled('prolongerPret')
+                ->answers(['statut' => true,
+                           'erreur' => '']);
+
+    $this->_potter->setDateRetour('2018-02-17');
+    $this->dispatch('/api/user/renew-loan/id/345_12',
+                    true,
+                    ["Authorization" => "Bearer nonos" ,
+                     "Content-Type" => "application/json"]);
+
+    $this->assertEquals(['status' => 'renewed',
+                         'date_due' => '2018-02-17'],
+                        json_decode($this->_response->getBody(), true));
+  }
+
+
+  /** @test */
+  public function resultShouldAnswerErrorOnSIGBError() {
+    $this->_sigb->whenCalled('prolongerPret')
+                ->answers(['statut' => false,
+                           'erreur' => 'could not renew']);
+
+    $this->dispatch('/api/user/renew-loan/id/345_12',
+                    true,
+                    ["Authorization" => "Bearer nonos" ,
+                     "Content-Type" => "application/json"]);
+
+    $this->assertEquals(['status' => 'error',
+                         'error' => 'could not renew'],
+                        json_decode($this->_response->getBody(), true));
+  }
+
+
+  /** @test */
+  public function resultShouldAnswerErrorOnLoanNotFound() {
+    $this->dispatch('/api/user/renew-loan/id/666_12',
+                    true,
+                    ["Authorization" => "Bearer nonos" ,
+                     "Content-Type" => "application/json"]);
+
+    $this->assertEquals(['status' => 'error',
+                         'error' => 'Prêt introuvable'],
+                        json_decode($this->_response->getBody(), true));
+  }
+
+}
+
+
+
+
+
+
 class Scenario_MobileApplication_UserAccountLoansWithoutTokenTest extends Scenario_MobileApplication_UserAccountTestCase {
   /** @test */
   public function withoutAuthorizationShouldAnswerInvalidRequest() {
@@ -202,13 +280,13 @@ class Scenario_MobileApplication_UserAccountLoansWithoutTokenTest extends Scenar
                      "Content-Type" => "application/json"]);
 
     $loans = json_decode($this->_response->getBody(), true);
-    $this->assertEquals(['title' => 'Potter',
-                         'author' => 'J.K.R',
-                         'date_due' => '1974-01-01',
-                         'loaned_by' => 'puppy',
-                         'library' => 'Annecy'
-                         ],
-                        $loans['loans'][0]);
+    $this->assertArraySubset(['title' => 'Potter',
+                              'author' => 'J.K.R',
+                              'date_due' => '1974-01-01',
+                              'loaned_by' => 'puppy',
+                              'library' => 'Annecy'
+                              ],
+                             $loans['loans'][0]);
   }
 }
 
@@ -389,6 +467,7 @@ class Scenario_MobileApplication_UserAccountWithTokenTest extends Scenario_Mobil
   /** @test */
   public function responseShouldContainsCardValidityAndLabel() {
     $this->assertEquals(['label' => 'Puppy',
+                         'login' => 'puppy',
                          'card' => [
                                     'id' =>  '234',
                                     'expire_at' => '2018-02-12']
@@ -396,4 +475,90 @@ class Scenario_MobileApplication_UserAccountWithTokenTest extends Scenario_Mobil
                         $this->_json['account']);
   }
 }
+
+
+
+class Scenario_MobileApplication_UserAccountHoldsWithTokenTest extends Scenario_MobileApplication_UserAccountTestCase {
+  protected
+    $_json;
+
+  public function setUp() {
+    parent::setUp();
+
+    $this->dispatch('/api/user/holds',
+                    true,
+                    ["Authorization" => "Bearer nonos" ,
+                     "Content-Type" => "application/json"]);
+
+    $this->_json = json_decode($this->_response->getBody(), true);
+  }
+
+
+  /** @test */
+  public function responseShouldContainsAfrodeeziaHold() {
+    $this->assertEquals(['id' => '345_18',
+                         'title' => 'Afrodeezia',
+                         'author' => 'Marcus Miller',
+                         'status' => 'En attente',
+                         'held_by' => 'puppy',
+                         'library' => 'Annecy',
+                         'record' => [ 'id' => '83',
+                                       'thumbnail' => 'http://img.com/marcus.jpg' ]
+                         ],
+                        $this->_json['holds'][0]);
+  }
+
+}
+
+
+
+
+class Scenario_MobileApplication_UserAccountCancelHoldTest extends Scenario_MobileApplication_UserAccountTestCase {
+  /** @test */
+  public function resultShouldAnswerSuccess() {
+    $this->_sigb->whenCalled('supprimerReservation')
+                ->answers(['statut' => true,
+                           'erreur' => '']);
+
+    $this->dispatch('/api/user/cancel-hold/id/345_18',
+                    true,
+                    ["Authorization" => "Bearer nonos" ,
+                     "Content-Type" => "application/json"]);
+
+    $this->assertEquals(['status' => 'canceled'],
+                        json_decode($this->_response->getBody(), true));
+  }
+
+
+  /** @test */
+  public function resultShouldAnswerErrorOnSIGBError() {
+    $this->_sigb->whenCalled('supprimerReservation')
+                ->answers(['statut' => false,
+                           'erreur' => 'could not cancel']);
+
+    $this->dispatch('/api/user/cancel-hold/id/345_18',
+                    true,
+                    ["Authorization" => "Bearer nonos" ,
+                     "Content-Type" => "application/json"]);
+
+    $this->assertEquals(['status' => 'error',
+                         'error' => 'could not cancel'],
+                        json_decode($this->_response->getBody(), true));
+  }
+
+
+  /** @test */
+  public function resultShouldAnswerErrorOnHoldNotFound() {
+    $this->dispatch('/api/user/cancel-hold/id/666_18',
+                    true,
+                    ["Authorization" => "Bearer nonos" ,
+                     "Content-Type" => "application/json"]);
+
+    $this->assertEquals(['status' => 'error',
+                         'error' => 'Réservation introuvable'],
+                        json_decode($this->_response->getBody(), true));
+  }
+
+}
+
 ?>
\ No newline at end of file