diff --git a/app/lib/common-libs/constants.ts b/app/lib/common-libs/constants.ts
index be669566c6875e5c55095b81780d84a99b67f5b6..bfe572eee15c2dbef702ac3c0742c359fb612fa6 100644
--- a/app/lib/common-libs/constants.ts
+++ b/app/lib/common-libs/constants.ts
@@ -300,7 +300,9 @@ export const CommonConstants = {
     SPECIAL_BLOCK
   },
 
-  BLOCK_MAX_TX_CHAINING_DEPTH: 5
+  BLOCK_MAX_TX_CHAINING_DEPTH: 5,
+  SYNC_BLOCKS_CHUNK: 250,
+  MILESTONES_PER_PAGE: 50,
 }
 
 function exact (regexpContent:string) {
diff --git a/app/modules/bma/index.ts b/app/modules/bma/index.ts
index 462ee2c857bfbb0c2f7097931e341b99f1ac23f1..815f2ba72268c3d98c007fac809df9d48d8fe4e2 100644
--- a/app/modules/bma/index.ts
+++ b/app/modules/bma/index.ts
@@ -153,19 +153,6 @@ export const BmaDependency = {
         if (program.upnp === true) {
           conf.upnp = true;
         }
-
-        // Configuration errors
-        if (!conf.nobma) {
-          if(!conf.ipv4 && !conf.ipv6){
-            throw new Error("No interface to listen to.");
-          }
-          if(!conf.remoteipv4 && !conf.remoteipv6 && !conf.remotehost){
-            throw new Error('No interface for remote contact.');
-          }
-          if (!conf.remoteport) {
-            throw new Error('No port for remote contact.');
-          }
-        }
       },
 
       beforeSave: async (conf:NetworkConfDTO, program:any) => {
@@ -179,6 +166,18 @@ export const BmaDependency = {
 
     service: {
       input: (server:Server, conf:NetworkConfDTO, logger:any) => {
+        // Configuration errors
+        if (!conf.nobma) {
+          if(!conf.ipv4 && !conf.ipv6){
+            throw new Error("No interface to listen to.");
+          }
+          if(!conf.remoteipv4 && !conf.remoteipv6 && !conf.remotehost){
+            throw new Error('No interface for remote contact.');
+          }
+          if (!conf.remoteport) {
+            throw new Error('No port for remote contact.');
+          }
+        }
         if (!conf.nobma) {
           server.addEndpointsDefinitions(() => Promise.resolve(getEndpoint(conf)))
           server.addWrongEndpointFilter((endpoints:string[]) => getWrongEndpoints(endpoints, server.conf.pair.pub))
diff --git a/app/modules/bma/lib/bma.ts b/app/modules/bma/lib/bma.ts
index 183125820a98dcc8ed1773bafed2a2273ae0f288..cf8424ea0a13bea9110a0e359911bf36ae6e3397 100644
--- a/app/modules/bma/lib/bma.ts
+++ b/app/modules/bma/lib/bma.ts
@@ -66,6 +66,8 @@ export const bma = function(server:Server, interfaces:NetworkInterface[], httpLo
     httpMethods.httpPOST( '/blockchain/block',                      (req:any) => blockchain.parseBlock(req),                BMALimitation.limitAsHighUsage());
     httpMethods.httpGET(  '/blockchain/block/:number',              (req:any) => blockchain.promoted(req),                  BMALimitation.limitAsHighUsage());
     httpMethods.httpGET(  '/blockchain/blocks/:count/:from',        (req:any) => blockchain.blocks(req),                    BMALimitation.limitAsHighUsage());
+    httpMethods.httpGET(  '/blockchain/milestones',                 (req:any) => blockchain.milestones(req),                BMALimitation.limitAsHighUsage());
+    httpMethods.httpGET(  '/blockchain/milestones/:page',           (req:any) => blockchain.milestones(req),                BMALimitation.limitAsHighUsage());
     httpMethods.httpGET(  '/blockchain/current',                    (req:any) => blockchain.current(),                      BMALimitation.limitAsHighUsage());
     httpMethods.httpGET(  '/blockchain/hardship/:search',           (req:any) => blockchain.hardship(req),                  BMALimitation.limitAsHighUsage());
     httpMethods.httpGET(  '/blockchain/difficulties',               (req:any) => blockchain.difficulties(),                 BMALimitation.limitAsHighUsage());
diff --git a/app/modules/bma/lib/constants.ts b/app/modules/bma/lib/constants.ts
index 2488dd573ac3579d7aa7dd097925e8029f6dd0ba..4ba022f2920eed2a23a4f16948bc6b2e7b907ee3 100644
--- a/app/modules/bma/lib/constants.ts
+++ b/app/modules/bma/lib/constants.ts
@@ -52,7 +52,8 @@ export const BMAConstants = {
     NO_CURRENT_BLOCK:                     { httpCode: 404, uerr: { ucode: 2010, message: "No current block" }},
     PEER_NOT_FOUND:                       { httpCode: 404, uerr: { ucode: 2012, message: "Peer not found" }},
     NO_IDTY_MATCHING_PUB_OR_UID:          { httpCode: 404, uerr: { ucode: 2021, message: "No identity matching this pubkey or uid" }},
-    TX_NOT_FOUND:                         { httpCode: 400, uerr: { ucode: 2034, message: 'Transaction not found' }}
+    TX_NOT_FOUND:                         { httpCode: 400, uerr: { ucode: 2034, message: 'Transaction not found' }},
+    INCORRECT_PAGE_NUMBER:                { httpCode: 400, uerr: { ucode: 2035, message: 'Incorrect page number' }}
 
     // New errors: range 3000-4000
   }
diff --git a/app/modules/bma/lib/controllers/blockchain.ts b/app/modules/bma/lib/controllers/blockchain.ts
index aef5eec9a24e41f1c7d98a575045a1f111d7101e..301076e86df4e01198d20f81b793cb1fa1a861e8 100644
--- a/app/modules/bma/lib/controllers/blockchain.ts
+++ b/app/modules/bma/lib/controllers/blockchain.ts
@@ -24,14 +24,14 @@ import {
   HttpDifficulties,
   HttpHardship,
   HttpMembership,
-  HttpMemberships,
+  HttpMemberships, HttpMilestonePage,
   HttpParameters,
   HttpStat
 } from "../dtos"
 
 const _                = require('underscore');
 const http2raw         = require('../http2raw');
-const toJson = require('../tojson');
+import * as toJson from "../tojson"
 
 export class BlockchainBinding extends AbstractController {
 
@@ -125,6 +125,11 @@ export class BlockchainBinding extends AbstractController {
     return blocks;
   }
 
+  async milestones(req: any): Promise<HttpMilestonePage> {
+    const page = ParametersService.getPage(req)
+    return this.server.milestones(page)
+  }
+
   async current(): Promise<HttpBlock> {
     const current = await this.server.dal.getCurrentBlockOrNull();
     if (!current) throw BMAConstants.ERRORS.NO_CURRENT_BLOCK;
diff --git a/app/modules/bma/lib/dtos.ts b/app/modules/bma/lib/dtos.ts
index 649f7c4254310e47dea4392411d30c32d705b8f8..871a769263f87e5fb231cb0b3390f10c4d08c1d5 100644
--- a/app/modules/bma/lib/dtos.ts
+++ b/app/modules/bma/lib/dtos.ts
@@ -967,3 +967,25 @@ export interface HttpSandboxes {
 export const LogLink = {
   link: String
 };
+
+export interface HttpMilestonePage {
+  totalPages: number
+  chunkSize: number
+  milestonesPerPage: number
+  currentPage?: number
+  blocks?: HttpBlock[]
+}
+
+export const Milestones = {
+  totalPages: Number,
+  chunkSize: Number,
+  milestonesPerPage: Number,
+  currentPage: Number,
+  "blocks": [Block]
+}
+
+export const MilestonesPage = {
+  totalPages: Number,
+  chunkSize: Number,
+  milestonesPerPage: Number,
+}
diff --git a/app/modules/bma/lib/parameters.ts b/app/modules/bma/lib/parameters.ts
index fed7b661e6b9f33fda042444a1ada168a7764a52..492e4da4c11de93471d2f29b60ca22f62a239893 100644
--- a/app/modules/bma/lib/parameters.ts
+++ b/app/modules/bma/lib/parameters.ts
@@ -73,6 +73,17 @@ export class ParametersService {
     return parseInt(req.params.minsig)
   }
 
+  static getPage(req:any): number|undefined {
+    if(!req.params.page){
+      return undefined
+    }
+    const matches = req.params.page.match(/\d+/)
+    if(!matches){
+      throw Error("`page` format is incorrect, must be an integer")
+    }
+    return parseInt(req.params.page)
+  }
+
   static getPubkey = function (req:any, callback:any){
     if(!req.params.pubkey){
       callback('Parameter `pubkey` is required');
diff --git a/server.ts b/server.ts
index 026ddf671f33b9ca98489bb4005e2257c2aad78b..097a09e204f2f184c231cb3668c2dc9a9e8741e7 100644
--- a/server.ts
+++ b/server.ts
@@ -24,7 +24,7 @@ import * as stream from "stream"
 import {KeyGen, randomKey} from "./app/lib/common-libs/crypto/keyring"
 import {parsers} from "./app/lib/common-libs/parsers/index"
 import {Cloneable} from "./app/lib/dto/Cloneable"
-import {DuniterDocument, duniterDocument2str} from "./app/lib/common-libs/constants"
+import {CommonConstants, DuniterDocument, duniterDocument2str} from "./app/lib/common-libs/constants"
 import {GlobalFifoPromise} from "./app/service/GlobalFifoPromise"
 import {BlockchainContext} from "./app/lib/computation/BlockchainContext"
 import {BlockDTO} from "./app/lib/dto/BlockDTO"
@@ -38,6 +38,9 @@ import {OtherConstants} from "./app/lib/other_constants"
 import {WS2PCluster} from "./app/modules/ws2p/lib/WS2PCluster"
 import {DBBlock} from "./app/lib/db/DBBlock"
 import { ProxiesConf } from './app/lib/proxy';
+import {BMAConstants} from "./app/modules/bma/lib/constants"
+import * as toJson from "./app/modules/bma/lib/tojson"
+import {HttpMilestonePage} from "./app/modules/bma/lib/dtos"
 
 export interface HookableServer {
   generatorGetJoinData: (...args:any[]) => Promise<any>
@@ -85,6 +88,7 @@ export class Server extends stream.Duplex implements HookableServer {
   BlockchainService:BlockchainService
   TransactionsService:TransactionService
   private documentFIFO:GlobalFifoPromise
+  milestoneArray: DBBlock[] = []
 
   constructor(home:string, memoryOnly:boolean, private overrideConf:any) {
     super({ objectMode: true })
@@ -669,4 +673,52 @@ export class Server extends stream.Duplex implements HookableServer {
   resetConfigHook(): Promise<any> {
     return Promise.resolve({})
   }
+
+  async milestones(page?: number): Promise<HttpMilestonePage> {
+    const chunkSize = CommonConstants.SYNC_BLOCKS_CHUNK
+    const milestonesPerPage = CommonConstants.MILESTONES_PER_PAGE
+    const current = await this.dal.getCurrentBlockOrNull();
+    if (!current) {
+      return {
+        totalPages: 0,
+        chunkSize,
+        milestonesPerPage
+      }
+    }
+    const topNumber = current.number - this.conf.forksize
+    const nbMilestones = (topNumber - (topNumber % chunkSize)) / chunkSize
+    const totalPages = (nbMilestones - (nbMilestones % milestonesPerPage)) / milestonesPerPage
+    if (page === undefined) {
+      return {
+        totalPages,
+        chunkSize,
+        milestonesPerPage
+      }
+    }
+    if (page > totalPages || page <= 0) throw BMAConstants.ERRORS.INCORRECT_PAGE_NUMBER
+    while (this.milestoneArray.length < page * milestonesPerPage) {
+      const lastMilestoneNumber = this.milestoneArray.length
+      // Feed the milestones
+      const newMilestones: DBBlock[] = []
+      for (let i = 1; i <= milestonesPerPage && this.milestoneArray.length < page * milestonesPerPage; i++) {
+        const b = await this.dal.getBlock((lastMilestoneNumber + i) * chunkSize - 1)
+        if (!b) {
+          throw Error('MILESTONE_BLOCK_NOT_FOUND')
+        }
+        newMilestones.push(b)
+      }
+      // As the process is async, another call to "milestones()" maybe have already filled in the milestones
+      if (this.milestoneArray.length < page * milestonesPerPage) {
+        this.milestoneArray = this.milestoneArray.concat(newMilestones)
+      }
+    }
+    const blocks = this.milestoneArray.slice((page - 1) * milestonesPerPage, page * milestonesPerPage)
+    return {
+      totalPages,
+      chunkSize,
+      milestonesPerPage,
+      currentPage: page,
+      blocks: blocks.map(b => toJson.block(b))
+    }
+  }
 }
\ No newline at end of file