diff --git a/.gitignore b/.gitignore
index 0a20bda443ea89da7e3abcaa41a1bdfdc4c3104a..4fab321086c39281baca0cfe8a9854f4f4f4c144 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@
 konnector-dev-config.json*
 fixtures/*
 data/*
+.importedData.json
 
 # NPM
 node_modules/
diff --git a/.vscode/settings.json b/.vscode/settings.json
index a5d64f0c9516fc743f84bdf8fb6a0676d241b962..4fb24b46c15da71ac3f3620c74cf91fd46830e3c 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,22 +1,3 @@
 {
-    "workbench.colorCustomizations": {
-        "activityBar.activeBackground": "#65c89b",
-        "activityBar.activeBorder": "#945bc4",
-        "activityBar.background": "#65c89b",
-        "activityBar.foreground": "#15202b",
-        "activityBar.inactiveForeground": "#15202b99",
-        "activityBarBadge.background": "#945bc4",
-        "activityBarBadge.foreground": "#e7e7e7",
-        "sash.hoverBorder": "#65c89b",
-        "statusBar.background": "#42b883",
-        "statusBar.foreground": "#15202b",
-        "statusBarItem.hoverBackground": "#359268",
-        "statusBarItem.remoteBackground": "#42b883",
-        "statusBarItem.remoteForeground": "#15202b",
-        "titleBar.activeBackground": "#42b883",
-        "titleBar.activeForeground": "#15202b",
-        "titleBar.inactiveBackground": "#42b88399",
-        "titleBar.inactiveForeground": "#15202b99"
-    },
-    "peacock.color": "#42b883"
+  "peacock.color": "#42b883"
 }
diff --git a/__tests__/core/contractActivation.spec.js b/__tests__/core/contractActivation.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..e294d21255e7ad83711315e14301e06624d1887b
--- /dev/null
+++ b/__tests__/core/contractActivation.spec.js
@@ -0,0 +1,95 @@
+const xml2js = require('xml2js')
+const { errors } = require('cozy-konnector-libs')
+const { activateContract } = require('../../src/core/contractActivation')
+
+const mockSoapRequest = jest.fn()
+jest.mock('easy-soap-request', () => async () => mockSoapRequest())
+
+const mockParseServiceId = jest.fn()
+jest.mock('../../src/helpers/parsing', () => ({
+  parseServiceId: () => mockParseServiceId(),
+}))
+
+const responseMock = {
+  response: {
+    body: 'mockedBody',
+  },
+}
+
+describe('activateContract', () => {
+  it('should return last contract if there is multiple contract ✅', async () => {
+    mockSoapRequest.mockResolvedValue(responseMock)
+    mockParseServiceId.mockReturnValue(78232791)
+
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValueOnce({})
+
+    try {
+      const serviceId = await activateContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1234567',
+        'POUET',
+        '1111111111111',
+        '01/01/2022',
+        '01/01/2023'
+      )
+      expect(serviceId).toBe(78232791)
+    } catch (error) {
+      expect(error).toBe(errors.LOGIN_FAILED)
+    }
+
+    mockParseServiceId.mockRestore()
+  })
+  it('should throw LOGIN_FAILED when request fail 🚫', async () => {
+    mockSoapRequest.mockRejectedValueOnce('reject')
+    try {
+      await activateContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1234567',
+        'POUET',
+        '1111111111111',
+        '01/01/2022',
+        '01/01/2023'
+      )
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.LOGIN_FAILED)
+    }
+
+    mockParseServiceId.mockRestore()
+  })
+  it('should throw LOGIN_FAILED when failing parsing 🚫', async () => {
+    mockSoapRequest.mockResolvedValueOnce(responseMock)
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValueOnce({
+      Envelope: {
+        Body: {
+          Fault: { detail: { erreur: { resultat: { $: { code: 401 } } } } },
+          faultstring: 'Mock error',
+        },
+      },
+    })
+    mockParseServiceId.mockImplementationOnce(() => {
+      throw new Error('error')
+    })
+    try {
+      await activateContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1234567',
+        'POUET',
+        '1111111111111',
+        '01/01/2022',
+        '01/01/2023'
+      )
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.LOGIN_FAILED)
+    }
+
+    mockParseServiceId.mockRestore()
+  })
+})
diff --git a/__tests__/core/contractStartDate.spec.js b/__tests__/core/contractStartDate.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e8aac92090be99a480233965af34394cd338e27
--- /dev/null
+++ b/__tests__/core/contractStartDate.spec.js
@@ -0,0 +1,90 @@
+const { errors } = require('cozy-konnector-libs')
+const { getContractStartDate } = require('../../src/core/contractStartDate')
+const xml2js = require('xml2js')
+
+const mockSoapRequest = jest.fn()
+jest.mock('easy-soap-request', () => async () => mockSoapRequest())
+
+const responseMock = {
+  response: {
+    body: `<?xml version="1.0" encoding="UTF-8"?>
+<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
+    <soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+        <ns7:consulterDonneesTechniquesContractuellesResponse xmlns:ns0="http://www.erdf.fr/tube/exposition/finalisation" xmlns:ns7="http://www.enedis.fr/sge/b2b/services/consulterdonneestechniquescontractuelles/v1.0">
+            <point id="19160781274487">
+                <donneesGenerales>
+                    <dateDerniereModificationFormuleTarifaireAcheminement>2021-08-01+02:00</dateDerniereModificationFormuleTarifaireAcheminement>
+                    <niveauOuvertureServices>2</niveauOuvertureServices>
+                </donneesGenerales>
+            </point>
+        </ns7:consulterDonneesTechniquesContractuellesResponse>
+    </soap:Body>
+</soapenv:Envelope>`,
+  },
+}
+
+const responseIssueMock = {
+  response: {
+    body: `<?xml version="1.0" encoding="UTF-8"?>
+<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
+    <soap:Body xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
+        <ns7:consulterDonneesTechniquesContractuellesResponse xmlns:ns0="http://www.erdf.fr/tube/exposition/finalisation" xmlns:ns7="http://www.enedis.fr/sge/b2b/services/consulterdonneestechniquescontractuelles/v1.0">
+            <point id="19160781274487">
+            </point>
+        </ns7:consulterDonneesTechniquesContractuellesResponse>
+    </soap:Body>
+</soapenv:Envelope>`,
+  },
+}
+
+describe('getContractStartDate', () => {
+  it('should return void when successfully got contract start date ✅', async () => {
+    mockSoapRequest.mockResolvedValueOnce(responseMock)
+    expect.assertions(1)
+    try {
+      await getContractStartDate(
+        'http://pouet.com',
+        'apiAuthKey',
+        'pouet@pouet.com',
+        '1111111111'
+      )
+      expect(true).toBeTruthy()
+    } catch (error) {
+      expect(true).toBe(false)
+    }
+  })
+
+  it('should throw VENDOR_DOWN when failing request 🚫', async () => {
+    mockSoapRequest.mockRejectedValueOnce('error')
+
+    try {
+      await getContractStartDate()
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.VENDOR_DOWN)
+    }
+  })
+
+  it('should throw NOT_EXISTING_DIRECTORY when failing parsing 🚫', async () => {
+    mockSoapRequest.mockResolvedValueOnce(responseIssueMock)
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValueOnce({
+      Envelope: {
+        Body: {
+          Fault: { detail: { erreur: { resultat: { $: { code: 401 } } } } },
+          faultstring: 'Mock error',
+        },
+      },
+    })
+    try {
+      await getContractStartDate(
+        'http://pouet.com',
+        'apiAuthKey',
+        'pouet@pouet.com',
+        '1111111111'
+      )
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.NOT_EXISTING_DIRECTORY)
+    }
+  })
+})
diff --git a/__tests__/core/contractTermination.spec.js b/__tests__/core/contractTermination.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..db71c233aef34168e62b1462c11e38511f60b608
--- /dev/null
+++ b/__tests__/core/contractTermination.spec.js
@@ -0,0 +1,86 @@
+const xml2js = require('xml2js')
+const { errors } = require('cozy-konnector-libs')
+const { terminateContract } = require('../../src/core/contractTermination')
+
+const mockSoapRequest = jest.fn()
+jest.mock('easy-soap-request', () => async () => mockSoapRequest())
+
+const responseMock = {
+  response: {
+    body: 'mockedBody',
+  },
+}
+
+describe('terminateContract', () => {
+  it('should terminate contract ✅', async () => {
+    mockSoapRequest.mockResolvedValue(responseMock)
+
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValueOnce({
+      Envelope: {
+        Body: {
+          Fault: { detail: { erreur: { resultat: { $: { code: 401 } } } } },
+          faultstring: 'Mock error',
+        },
+      },
+    })
+    try {
+      const serviceId = await terminateContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1111111111111',
+        '1234567'
+      )
+      expect(serviceId).toEqual({
+        Envelope: {
+          Body: {
+            Fault: { detail: { erreur: { resultat: { $: { code: 401 } } } } },
+            faultstring: 'Mock error',
+          },
+        },
+      })
+    } catch (error) {
+      expect(error).toBe(errors.VENDOR_DOWN)
+    }
+  })
+  it('should throw VENDOR_DOWN on bad request🚫', async () => {
+    mockSoapRequest.mockRejectedValueOnce('reject')
+
+    try {
+      await terminateContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1111111111111',
+        '1234567'
+      )
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.VENDOR_DOWN)
+    }
+  })
+  it('should throw VENDOR_DOWN 🚫', async () => {
+    mockSoapRequest.mockResolvedValue(responseMock)
+
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValueOnce({
+      Envelope: {
+        Body: {
+          Fault: {},
+        },
+      },
+    })
+
+    try {
+      await terminateContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1111111111111',
+        '1234567'
+      )
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.VENDOR_DOWN)
+    }
+  })
+})
diff --git a/__tests__/core/contractVerification.spec.js b/__tests__/core/contractVerification.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..12eddf0f97b82756aa96b042deb7764ee9a185cd
--- /dev/null
+++ b/__tests__/core/contractVerification.spec.js
@@ -0,0 +1,229 @@
+const xml2js = require('xml2js')
+const { errors } = require('cozy-konnector-libs')
+const { verifyContract } = require('../../src/core/contractVerification')
+
+const mockSoapRequest = jest.fn()
+jest.mock('easy-soap-request', () => async () => mockSoapRequest())
+
+const mockParseContracts = jest.fn()
+jest.mock('../../src/helpers/parsing', () => ({
+  parseContracts: () => mockParseContracts(),
+}))
+
+const responseMock = {
+  response: {
+    body: 'mockedBody',
+  },
+}
+
+describe('verifyContract', () => {
+  it('should return last contract if there is multiple contract ✅', async () => {
+    mockSoapRequest.mockResolvedValue(responseMock)
+    mockParseContracts.mockReturnValue([
+      {
+        serviceSouscritId: 78232791,
+        etatCode: 'ACTIF',
+        serviceSouscritLibelle:
+          'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+      },
+      {
+        serviceSouscritId: 78232793,
+        etatCode: 'TERMINE',
+        serviceSouscritLibelle:
+          'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+      },
+    ])
+
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValue(
+      {
+        Envelope: {
+          Body: {
+            rechercherServicesSouscritsMesuresResponse: {
+              servicesSouscritsMesures: {
+                serviceSouscritMesures: [
+                  {
+                    serviceSouscritId: 78232791,
+                    etatCode: 'ACTIF',
+                    serviceSouscritLibelle:
+                      'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+                  },
+                  {
+                    serviceSouscritId: 78232793,
+                    etatCode: 'TERMINE',
+                    serviceSouscritLibelle:
+                      'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+                  },
+                ],
+              },
+            },
+          },
+        },
+      }.toString()
+    )
+
+    try {
+      const serviceId = await verifyContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1234567',
+        '1111111111111'
+      )
+      expect(serviceId).toBe(78232791)
+    } catch (error) {
+      expect(error).toBe(errors.LOGIN_FAILED)
+    }
+
+    mockParseContracts.mockRestore()
+  })
+  it('should return last contract if there is one contract ✅', async () => {
+    mockSoapRequest.mockResolvedValue(responseMock)
+    mockParseContracts.mockReturnValue({
+      serviceSouscritId: 78232791,
+      etatCode: 'ACTIF',
+      serviceSouscritLibelle:
+        'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+    })
+
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValue(
+      {
+        Envelope: {
+          Body: {
+            rechercherServicesSouscritsMesuresResponse: {
+              servicesSouscritsMesures: {
+                serviceSouscritMesures: [
+                  {
+                    serviceSouscritId: 78232791,
+                    etatCode: 'ACTIF',
+                    serviceSouscritLibelle:
+                      'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+                  },
+                  {
+                    serviceSouscritId: 78232793,
+                    etatCode: 'TERMINE',
+                    serviceSouscritLibelle:
+                      'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+                  },
+                ],
+              },
+            },
+          },
+        },
+      }.toString()
+    )
+
+    try {
+      const serviceId = await verifyContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1234567',
+        '1111111111111'
+      )
+      expect(serviceId).toBe(78232791)
+    } catch (error) {
+      expect(error).toBe(errors.LOGIN_FAILED)
+    }
+
+    mockParseContracts.mockRestore()
+  })
+  it('should return null if last contract is TERMINE 🚫', async () => {
+    mockSoapRequest.mockResolvedValue(responseMock)
+    mockParseContracts.mockReturnValue([
+      {
+        serviceSouscritId: 78232791,
+        etatCode: 'TERMINE',
+        serviceSouscritLibelle:
+          'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+      },
+      {
+        serviceSouscritId: 78232793,
+        etatCode: 'TERMINE',
+        serviceSouscritLibelle:
+          'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+      },
+    ])
+
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValue(
+      {
+        Envelope: {
+          Body: {
+            rechercherServicesSouscritsMesuresResponse: {
+              servicesSouscritsMesures: {
+                serviceSouscritMesures: [
+                  {
+                    serviceSouscritId: 78232791,
+                    etatCode: 'TERMINE',
+                    serviceSouscritLibelle:
+                      'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+                  },
+                  {
+                    serviceSouscritId: 78232793,
+                    etatCode: 'TERMINE',
+                    serviceSouscritLibelle:
+                      'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+                  },
+                ],
+              },
+            },
+          },
+        },
+      }.toString()
+    )
+
+    try {
+      const serviceId = await verifyContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1234567',
+        '1111111111111'
+      )
+      expect(serviceId).toBe(null)
+    } catch (error) {
+      expect(error).toBe(errors.LOGIN_FAILED)
+    }
+
+    mockParseContracts.mockRestore()
+  })
+  it('should return LOGIN_FAILED if issue in request 🚫', async () => {
+    mockSoapRequest.mockRejectedValueOnce('reject')
+
+    try {
+      await verifyContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1234567',
+        '1111111111111'
+      )
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.LOGIN_FAILED)
+    }
+  })
+  it('should return LOGIN_FAILED if issue in parsing 🚫', async () => {
+    mockSoapRequest.mockResolvedValue(responseMock)
+    jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValueOnce({
+      Envelope: {
+        Body: {
+          Fault: { detail: { erreur: { resultat: { $: { code: 401 } } } } },
+          faultstring: 'Mock error',
+        },
+      },
+    })
+
+    try {
+      await verifyContract(
+        'http://test.com',
+        '111',
+        'login@log.com',
+        '1234567',
+        '1111111111111'
+      )
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.LOGIN_FAILED)
+    }
+  })
+})
diff --git a/__tests__/findUserPdl.spec.js b/__tests__/core/findUserPdl.spec.js
similarity index 77%
rename from __tests__/findUserPdl.spec.js
rename to __tests__/core/findUserPdl.spec.js
index fbf854b832d6362b409f90c044383236b16fbc85..140201b691964a0dc8a1ae75f79b92589e5d9697 100644
--- a/__tests__/findUserPdl.spec.js
+++ b/__tests__/core/findUserPdl.spec.js
@@ -1,14 +1,21 @@
 const xml2js = require('xml2js')
 const { errors } = require('cozy-konnector-libs')
-const { findUserPdl } = require('../src/findUserPdl')
+const { findUserPdl } = require('../../src/core/findUserPdl')
 
 const mockSoapRequest = jest.fn()
 jest.mock('easy-soap-request', () => async () => mockSoapRequest())
 
-jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValue('response')
+jest.spyOn(xml2js, 'parseStringPromise').mockResolvedValue({
+  Envelope: {
+    Body: {
+      Fault: { detail: { erreur: { resultat: { $: { code: 401 } } } } },
+      faultstring: 'Mock error',
+    },
+  },
+})
 
 const mockParseUserPdl = jest.fn()
-jest.mock('../src/parsing', () => ({
+jest.mock('../../src/helpers/parsing', () => ({
   parseUserPdl: () => mockParseUserPdl(),
 }))
 
@@ -22,7 +29,7 @@ describe('recherchePoint', () => {
   it('should throw LOGIN_FAILED for too many responses', async () => {
     mockSoapRequest.mockResolvedValue(responseMock)
     mockParseUserPdl.mockImplementationOnce(() => {
-      throw new Error('fail')
+      throw new Error('Error')
     })
 
     try {
@@ -46,6 +53,7 @@ describe('recherchePoint', () => {
   it('should return a correct pdl number', async () => {
     mockSoapRequest.mockResolvedValue(responseMock)
     mockParseUserPdl.mockResolvedValue('12345')
+
     expect(await findUserPdl()).toBe('12345')
   })
 })
diff --git a/__tests__/verifyUserIdentity.spec.js b/__tests__/core/verifyUserIdentity.spec.js
similarity index 56%
rename from __tests__/verifyUserIdentity.spec.js
rename to __tests__/core/verifyUserIdentity.spec.js
index 98263253c4a140dee01ec3300581336f4bb762d2..37a585c9e32489f4bde41a31a2ade3a8807472ae 100644
--- a/__tests__/verifyUserIdentity.spec.js
+++ b/__tests__/core/verifyUserIdentity.spec.js
@@ -1,20 +1,20 @@
 const { errors } = require('cozy-konnector-libs')
-const { verifyUserIdentity } = require('../src/verifyUserIdentity')
+const { verifyUserIdentity } = require('../../src/core/verifyUserIdentity')
 
-jest.mock('../src/requests/insee', () => ({
+jest.mock('../../src/requests/insee', () => ({
   getInseeCode: jest.fn().mockResolvedValue(69),
 }))
 
-jest.mock('../src/findUserPdl', () => ({
+jest.mock('../../src/core/findUserPdl', () => ({
   findUserPdl: jest.fn().mockResolvedValue('12345'),
 }))
 
-jest.mock('../src/index', () => ({
+jest.mock('../../src/index', () => ({
   start: jest.fn(),
 }))
 
 describe('verifyUserIdentity', () => {
-  it('should throw LOGIN_FAILED when pdl give and recieved are NOT matching 🚫', async () => {
+  it('should throw LOGIN_FAILED when pdl given and recieved are NOT matching 🚫', async () => {
     try {
       await verifyUserIdentity(
         {
@@ -32,6 +32,25 @@ describe('verifyUserIdentity', () => {
       expect(error).toBe(errors.LOGIN_FAILED)
     }
   })
+  it('should throw TERMS_VERSION_MISMATCH when pdl give and recieved are NOT matching on alternate start 🚫', async () => {
+    try {
+      await verifyUserIdentity(
+        {
+          name: 'John',
+          address: '1 street',
+          pointId: 987654321,
+          postalCode: '69069',
+        },
+        'azertyuiop',
+        'apiKey',
+        'login@user.com',
+        true
+      )
+      expect(true).toBe(false)
+    } catch (error) {
+      expect(error).toBe(errors.TERMS_VERSION_MISMATCH)
+    }
+  })
 
   it('should return void when pdl give and recieved are matching ✅', async () => {
     expect.assertions(1)
diff --git a/__tests__/aggregate.spec.js b/__tests__/helpers/aggregate.spec.js
similarity index 96%
rename from __tests__/aggregate.spec.js
rename to __tests__/helpers/aggregate.spec.js
index 0b43f693f937ad3f72476e9220f92431eed00f40..f5b64cb00bdcd829a884269fb73ab50d2d28e008 100644
--- a/__tests__/aggregate.spec.js
+++ b/__tests__/helpers/aggregate.spec.js
@@ -1,4 +1,4 @@
-const { buildAgregatedData } = require('../src/aggregate')
+const { buildAgregatedData } = require('../../src/helpers/aggregate')
 const { cozyClient } = require('cozy-konnector-libs')
 
 describe('buildAgregatedData', () => {
diff --git a/__tests__/helpers/parsing.spec.js b/__tests__/helpers/parsing.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..37fefc0fb31fc6b01f85d632690beba73fe40d7c
--- /dev/null
+++ b/__tests__/helpers/parsing.spec.js
@@ -0,0 +1,152 @@
+const {
+  parseUserPdl,
+  parseContractStartDate,
+  parseContracts,
+  parseServiceId,
+  parseSgeXmlData,
+  formateDataForDoctype,
+  parseTags,
+  parseValue,
+} = require('../../src/helpers/parsing')
+describe('parsing', () => {
+  it('should parse userPdl', () => {
+    const result = {
+      Envelope: {
+        Body: {
+          rechercherPointResponse: { points: { point: { $: { id: 1 } } } },
+        },
+      },
+    }
+    const reply = parseUserPdl(result)
+    expect(reply).toEqual(1)
+  })
+  it('should parse contract start date', () => {
+    const result = {
+      Envelope: {
+        Body: {
+          consulterDonneesTechniquesContractuellesResponse: {
+            point: {
+              donneesGenerales: {
+                dateDerniereModificationFormuleTarifaireAcheminement:
+                  '01/01/2022',
+              },
+            },
+          },
+        },
+      },
+    }
+    const reply = parseContractStartDate(result)
+    expect(reply).toEqual('01/01/2022')
+  })
+  it('should parse contract', () => {
+    const result = {
+      Envelope: {
+        Body: {
+          rechercherServicesSouscritsMesuresResponse: {
+            servicesSouscritsMesures: {
+              serviceSouscritMesures: [
+                {
+                  serviceSouscritId: 78232791,
+                  etatCode: 'TERMINE',
+                  serviceSouscritLibelle:
+                    'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+                },
+                {
+                  serviceSouscritId: 78232793,
+                  etatCode: 'TERMINE',
+                  serviceSouscritLibelle:
+                    'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+                },
+              ],
+            },
+          },
+        },
+      },
+    }
+    const reply = parseContracts(result)
+    expect(reply).toEqual([
+      {
+        serviceSouscritId: 78232791,
+        etatCode: 'TERMINE',
+        serviceSouscritLibelle:
+          'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+      },
+      {
+        serviceSouscritId: 78232793,
+        etatCode: 'TERMINE',
+        serviceSouscritLibelle:
+          'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+      },
+    ])
+  })
+
+  it('should parse service id', () => {
+    const result = {
+      Envelope: {
+        Body: {
+          commanderCollectePublicationMesuresResponse: {
+            serviceSouscritId: 12,
+          },
+        },
+      },
+    }
+    const reply = parseServiceId(result)
+    expect(reply).toEqual(12)
+  })
+  it('should parse consumption data', () => {
+    const result = {
+      Envelope: {
+        Body: {
+          consulterMesuresDetailleesResponse: {
+            grandeur: {
+              mesure: {
+                v: 14361,
+                d: '2021-08-01T00:00:00.000+02:00',
+              },
+            },
+          },
+        },
+      },
+    }
+    const reply = parseSgeXmlData(result)
+    expect(reply).toEqual({
+      v: 14361,
+      d: '2021-08-01T00:00:00.000+02:00',
+    })
+  })
+  it('should format data for doctype', async () => {
+    const data = [
+      {
+        v: 14361,
+        d: '2021-08-01T00:00:00.000+02:00',
+      },
+      {
+        v: 11,
+        d: '2021-08-02T00:00:00.000+02:00',
+      },
+    ]
+    const reply = await formateDataForDoctype(data)
+    expect(reply).toEqual([
+      { day: 1, hour: 0, load: 14361, minute: 0, month: 8, year: 2021 },
+      { day: 2, hour: 0, load: 11, minute: 0, month: 8, year: 2021 },
+    ])
+  })
+
+  it('should parseTag with :', () => {
+    const reply = parseTags('test:tag')
+    expect(reply).toBe('tag')
+  })
+  it('should parseTag', () => {
+    const reply = parseTags('testtag')
+    expect(reply).toBe('testtag')
+  })
+
+  it('should parse value from Wh to KWh', () => {
+    const reply = parseValue(14361, 'v')
+    expect(reply).toBe(14.36)
+  })
+  it('should not parse value', () => {
+    const reply = parseValue(14361, 'w')
+    expect(reply).toBe(14361)
+  })
+})
diff --git a/__tests__/requests/bo.spec.js b/__tests__/requests/bo.spec.js
index 7e2102956c86c644a604a5de28d3e6aafcbca11b..b4d3f8b366857d912489fb97ee10358c59ea851b 100644
--- a/__tests__/requests/bo.spec.js
+++ b/__tests__/requests/bo.spec.js
@@ -1,83 +1,200 @@
-const { createBoConsent, getBoConsent } = require('../../src/requests/bo')
-const { default: axios } = require('axios')
+const {
+  createBoConsent,
+  getBoConsent,
+  updateBoConsent,
+  deleteBoConsent,
+} = require('../../src/requests/bo')
+const axios = require('axios')
 const { errors } = require('cozy-konnector-libs')
 
 jest.mock('axios')
 describe('Backoffice routes', () => {
   describe('createBoConsent', () => {
     it('should send consent to BO', async () => {
-      axios.post.mockResolvedValueOnce({ id: 1 })
-      const consent = await createBoConsent({
-        pdl: 11111111111111,
-        name: 'POUET',
-        adresse: '20 rue du lac',
+      axios.post.mockImplementationOnce(() => {
+        return {
+          data: {
+            ID: 1,
+            firstname: 'mr',
+            lastname: 'POUET',
+            pointId: 11111111111111,
+            postalCode: '69003',
+            address: '20 rue du lac',
+            inseeCode: '69383',
+          },
+        }
+      })
+      const consent = await createBoConsent(
+        'http://test.com',
+        'token',
+        11111111111111,
+        'POUET',
+        'mr',
+        '20 rue du lac',
+        '69003',
+        '69383'
+      )
+      expect(consent).toEqual({
+        ID: 1,
+        firstname: 'mr',
+        lastname: 'POUET',
+        pointId: 11111111111111,
         postalCode: '69003',
+        address: '20 rue du lac',
         inseeCode: '69383',
       })
-      expect(consent).toBe({ id: 1 })
     })
     it('should handle unavailable BO', async () => {
-      axios.post.mockImplementationOnce(() =>
-        Promise.reject(errors.MAINTENANCE)
-      )
+      axios.post.mockImplementationOnce(() => Promise.reject('fail'))
       try {
-        await createBoConsent({
-          pdl: 11111111111111,
-          name: 'POUET',
-          adresse: '20 rue du lac',
-          postalCode: '69003',
-          inseeCode: '69383',
-        })
+        await createBoConsent(
+          'http://test.com',
+          'token',
+          11111111111111,
+          'POUET',
+          'mr',
+          '20 rue du lac',
+          '69003',
+          '69383'
+        )
         expect(true).toBe(false)
       } catch (e) {
         expect(e).toBe(errors.MAINTENANCE)
       }
     })
   })
-  describe('getBoConsent', () => {
-    it('should get consent from BO', async () => {
-      axios.get.mockResolvedValueOnce({
-        id: 1,
-        pointId: 11111111111111,
-        name: 'POUET',
-        adresse: '20 rue du lac',
-        postalCode: '69003',
-        inseeCode: '69383',
+  describe('updateBoConsent', () => {
+    it('should update consent to BO', async () => {
+      axios.put.mockImplementationOnce(() => {
+        return {
+          data: {
+            ID: 1,
+            firstname: 'mr',
+            lastname: 'POUET',
+            pointId: 11111111111111,
+            postalCode: '69003',
+            address: '20 rue du lac',
+            inseeCode: '69383',
+            serviceId: '123456',
+          },
+        }
       })
-      const consent = await getBoConsent(1)
-      expect(consent).toBe({
+      const consent = await updateBoConsent(
+        'http://test.com',
+        'token',
+        {
+          ID: 1,
+          firstname: 'mr',
+          lastname: 'POUET',
+          pointId: 11111111111111,
+          postalCode: '69003',
+          address: '20 rue du lac',
+          inseeCode: '69383',
+        },
+        '123456'
+      )
+      expect(consent).toEqual({
+        ID: 1,
+        firstname: 'mr',
+        lastname: 'POUET',
         pointId: 11111111111111,
-        name: 'POUET',
-        adresse: '20 rue du lac',
         postalCode: '69003',
+        address: '20 rue du lac',
         inseeCode: '69383',
+        serviceId: '123456',
       })
     })
-    it('should get consent from BO with service id', async () => {
-      axios.get.mockResolvedValueOnce({
-        id: 1,
+    it('should handle unavailable BO', async () => {
+      axios.put.mockImplementationOnce(() => Promise.reject('fail'))
+      try {
+        await updateBoConsent(
+          'http://test.com',
+          'token',
+          {
+            ID: 1,
+            firstname: 'mr',
+            lastname: 'POUET',
+            pointId: 11111111111111,
+            postalCode: '69003',
+            address: '20 rue du lac',
+            inseeCode: '69383',
+          },
+          '123456'
+        )
+        expect(true).toBe(false)
+      } catch (e) {
+        expect(e).toBe(errors.MAINTENANCE)
+      }
+    })
+  })
+
+  describe('deleteBoConsent', () => {
+    it('should delete consent to BO', async () => {
+      axios.delete.mockImplementationOnce(() => {
+        return {
+          data: {
+            ID: 1,
+            firstname: 'mr',
+            lastname: 'POUET',
+            pointId: 11111111111111,
+            postalCode: '69003',
+            address: '20 rue du lac',
+            inseeCode: '69383',
+            serviceId: '123456',
+          },
+        }
+      })
+      const consent = await deleteBoConsent('http://test.com', 'token', 1)
+      expect(consent).toEqual({
+        ID: 1,
+        firstname: 'mr',
+        lastname: 'POUET',
         pointId: 11111111111111,
-        name: 'POUET',
-        adresse: '20 rue du lac',
         postalCode: '69003',
+        address: '20 rue du lac',
         inseeCode: '69383',
-        serviceId: 'abcde',
+        serviceId: '123456',
+      })
+    })
+    it('should handle unavailable BO', async () => {
+      axios.put.mockImplementationOnce(() => Promise.reject('fail'))
+      try {
+        await deleteBoConsent('http://test.com', 'token', 1)
+        expect(true).toBe(false)
+      } catch (e) {
+        expect(e).toBe(errors.MAINTENANCE)
+      }
+    })
+  })
+  describe('getBoConsent', () => {
+    it('should get consent from BO', async () => {
+      axios.get.mockImplementationOnce(() => {
+        return {
+          data: {
+            ID: 1,
+            pointId: 11111111111111,
+            name: 'POUET',
+            adresse: '20 rue du lac',
+            postalCode: '69003',
+            inseeCode: '69383',
+          },
+        }
       })
-      const consent = await getBoConsent(1)
-      expect(consent.serviceId).toBeTruthy()
-      expect(consent).toBe({
+      const consent = await getBoConsent('http://test.com', 'token', 1)
+      expect(consent).toEqual({
+        ID: 1,
         pointId: 11111111111111,
         name: 'POUET',
         adresse: '20 rue du lac',
         postalCode: '69003',
         inseeCode: '69383',
-        serviceId: 'abcde',
       })
     })
+
     it('should handle unavailable BO', async () => {
       axios.get.mockImplementationOnce(() => Promise.reject(errors.MAINTENANCE))
       try {
-        await createBoConsent({
+        await getBoConsent({
           pointId: 11111111111111,
           name: 'POUET',
           adresse: '20 rue du lac',
diff --git a/__tests__/requests/cozy.spec.js b/__tests__/requests/cozy.spec.js
new file mode 100644
index 0000000000000000000000000000000000000000..ab0b4aa303cbe7bdd973508cc49b19b5a5b9be82
--- /dev/null
+++ b/__tests__/requests/cozy.spec.js
@@ -0,0 +1,70 @@
+const { cozyClient } = require('cozy-konnector-libs')
+const { getAccount, saveAccountData } = require('../../src/requests/cozy')
+
+const mockUpdateOrCreate = jest.fn()
+
+describe('getAccount', () => {
+  it('should find account with provided ID', async () => {
+    const spy = jest.spyOn(cozyClient.data, 'findAll')
+    spy.mockResolvedValueOnce([
+      {
+        _id: '123456',
+        account_type: '123456',
+        auth: {
+          address: '12 rue du pouet',
+          city: 'Lyon',
+          firstname: 'Jean',
+          lastname: 'POUET',
+          pointId: '1234567891234567',
+          postalCode: '69007',
+        },
+      },
+      { _id: '1111111', account_type: '1111111' },
+    ])
+    const account = await getAccount('123456')
+    expect(account).toEqual({
+      _id: '123456',
+      account_type: '123456',
+      auth: {
+        address: '12 rue du pouet',
+        city: 'Lyon',
+        firstname: 'Jean',
+        lastname: 'POUET',
+        pointId: '1234567891234567',
+        postalCode: '69007',
+      },
+    })
+  })
+})
+
+describe('saveAccountData', () => {
+  jest.mock('cozy-konnector-libs', () => ({
+    updateOrCreate: () => mockUpdateOrCreate(),
+  }))
+
+  it('should save data to account', async () => {
+    const spy = jest.spyOn(cozyClient.data, 'findAll')
+    spy.mockResolvedValueOnce([
+      {
+        _id: '123456',
+        account_type: '123456',
+        auth: {
+          address: '12 rue du pouet',
+          city: 'Lyon',
+          firstname: 'Jean',
+          lastname: 'POUET',
+          pointId: '1234567891234567',
+          postalCode: '69007',
+        },
+      },
+      { _id: '1111111', account_type: '1111111' },
+    ])
+    mockUpdateOrCreate.mockResolvedValueOnce({
+      _id: '1111111',
+      account_type: '1111111',
+      data: { name: 'pouet' },
+    })
+    const account = await saveAccountData('1111111', { name: 'pouet' })
+    expect(account[0].data).toEqual({ name: 'pouet' })
+  })
+})
diff --git a/__tests__/requests/sge.spec.js b/__tests__/requests/sge.spec.js
index 28770b2b649b4aa16a4fc2149a449585baa9de6a..86ae6922c2207033ad465ab897002665e99d8d1a 100644
--- a/__tests__/requests/sge.spec.js
+++ b/__tests__/requests/sge.spec.js
@@ -1,6 +1,223 @@
+const xml2js = require('xml2js')
+const { parseTags, parseValue } = require('../../src/helpers/parsing')
+const {
+  consultationMesuresDetaillees,
+  consultationMesuresDetailleesMaxPower,
+  consulterDonneesTechniquesContractuelles,
+  rechercherPoint,
+  rechercherServicesSouscritsMesures,
+  commanderCollectePublicationMesures,
+  commanderArretServiceSouscritMesures,
+} = require('../../src/requests/sge')
+
 describe('Sge routes', () => {
-  //TODO: write TU
-  it('should be true', () => {
-    expect(true).toBe(true)
+  describe('consultationMesuresDetaillees', () => {
+    it('should format request with default params', async () => {
+      const reply = consultationMesuresDetaillees(
+        1111,
+        'test@grandlyon.com',
+        '2022-08-01',
+        '2022-08-20'
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+      const data = parsedReply.Envelope.Body.consulterMesuresDetaillees.demande
+      expect(Object.keys(data).length).toEqual(10)
+      expect(data.mesuresTypeCode).toEqual('ENERGIE')
+      expect(data.grandeurPhysique).toEqual('EA')
+    })
+    it('should format request with given mesure type and unit', async () => {
+      const reply = consultationMesuresDetaillees(
+        1111,
+        'test@grandlyon.com',
+        '2022-08-01',
+        '2022-08-20',
+        'mesurePouet',
+        'POUET'
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+      const data = parsedReply.Envelope.Body.consulterMesuresDetaillees.demande
+      expect(Object.keys(data).length).toEqual(10)
+      expect(data.mesuresTypeCode).toEqual('mesurePouet')
+      expect(data.grandeurPhysique).toEqual('POUET')
+    })
+  })
+  describe('consultationMesuresDetailleesMaxPower', () => {
+    it('should format request with default params', async () => {
+      const reply = consultationMesuresDetailleesMaxPower(
+        1111,
+        'test@grandlyon.com',
+        '2022-08-01',
+        '2022-08-20'
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+      const data = parsedReply.Envelope.Body.consulterMesuresDetaillees.demande
+      expect(Object.keys(data).length).toEqual(11)
+      expect(data.mesuresPas).toEqual('P1D')
+      expect(data.mesuresTypeCode).toEqual('PMAX')
+      expect(data.grandeurPhysique).toEqual('PMA')
+    })
+    it('should format request with given mesure type and unit', async () => {
+      const reply = consultationMesuresDetailleesMaxPower(
+        1111,
+        'test@grandlyon.com',
+        '2022-08-01',
+        '2022-08-20',
+        'mesurePouet',
+        'POUET'
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+      const data = parsedReply.Envelope.Body.consulterMesuresDetaillees.demande
+      expect(Object.keys(data).length).toEqual(11)
+      expect(data.mesuresTypeCode).toEqual('mesurePouet')
+      expect(data.grandeurPhysique).toEqual('POUET')
+    })
+  })
+  describe('consulterDonneesTechniquesContractuelles', () => {
+    it('should format request', async () => {
+      const reply = consulterDonneesTechniquesContractuelles(
+        1111,
+        'test@grandlyon.com'
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+      const data =
+        parsedReply.Envelope.Body.consulterDonneesTechniquesContractuelles
+      expect(Object.keys(data).length).toEqual(3)
+      expect(data.autorisationClient).toEqual('true')
+    })
+  })
+  describe('rechercherPoint', () => {
+    it('should format request', async () => {
+      const reply = rechercherPoint(
+        'test@grandlyon.com',
+        'toto',
+        '69007',
+        '69387',
+        '20 rue du lac'
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+      const data = parsedReply.Envelope.Body
+      expect(Object.keys(data.rechercherPoint).length).toEqual(2)
+      expect(Object.keys(data.rechercherPoint.criteres).length).toEqual(3)
+      expect(
+        Object.keys(data.rechercherPoint.criteres.adresseInstallation).length
+      ).toEqual(3)
+      expect(data.rechercherPoint.criteres.rechercheHorsPerimetre).toEqual(
+        'true'
+      )
+    })
+  })
+  describe('rechercherServicesSouscritsMesures', () => {
+    it('should format request', async () => {
+      const reply = rechercherServicesSouscritsMesures(
+        'test@grandlyon.com',
+        '69007',
+        1111233
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+
+      const data = parsedReply.Envelope.Body
+      expect(
+        Object.keys(data.rechercherServicesSouscritsMesures).length
+      ).toEqual(2)
+      expect(
+        Object.keys(data.rechercherServicesSouscritsMesures.criteres).length
+      ).toEqual(2)
+    })
+  })
+  describe('commanderCollectePublicationMesures', () => {
+    it('should format request', async () => {
+      const reply = commanderCollectePublicationMesures(
+        'test@grandlyon.com',
+        '12345',
+        '1111233',
+        'toto',
+        '2021-08-01',
+        '2021-08-02'
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+
+      const data = parsedReply.Envelope.Body
+      expect(
+        Object.keys(data.commanderCollectePublicationMesures.demande).length
+      ).toEqual(2)
+      expect(
+        Object.keys(
+          data.commanderCollectePublicationMesures.demande.donneesGenerales
+        ).length
+      ).toEqual(4)
+      expect(
+        Object.keys(
+          data.commanderCollectePublicationMesures.demande.accesMesures
+        ).length
+      ).toEqual(10)
+      expect(
+        Object.keys(
+          data.commanderCollectePublicationMesures.demande.accesMesures
+            .declarationAccordClient
+        ).length
+      ).toEqual(2)
+    })
+  })
+  describe('commanderArretServiceSouscritMesures', () => {
+    it('should format request', async () => {
+      const reply = commanderArretServiceSouscritMesures(
+        'test@grandlyon.com',
+        '12345',
+        '1111233',
+        '3654'
+      )
+      const parsedReply = await xml2js.parseStringPromise(reply, {
+        tagNameProcessors: [parseTags],
+        valueProcessors: [parseValue],
+        explicitArray: false,
+      })
+
+      const data = parsedReply.Envelope.Body
+      expect(
+        Object.keys(data.commanderArretServiceSouscritMesures.demande).length
+      ).toEqual(2)
+      expect(
+        Object.keys(
+          data.commanderArretServiceSouscritMesures.demande.donneesGenerales
+        ).length
+      ).toEqual(4)
+      expect(
+        Object.keys(
+          data.commanderArretServiceSouscritMesures.demande.arretServiceSouscrit
+        ).length
+      ).toEqual(1)
+    })
   })
 })
diff --git a/manifest.konnector b/manifest.konnector
index e26d1d5f5e99005e71c97dea70c3171a24e71b9e..9f38cbaea11eb65707d7eaf3090e85286b8bab35 100644
--- a/manifest.konnector
+++ b/manifest.konnector
@@ -11,8 +11,23 @@
   "categories": ["energy"],
   "frequency": "daily",
   "fields": {
+    "firstname": {
+      "type": "string"
+    },
+    "lastname": {
+      "type": "string"
+    },
+    "address": {
+      "type": "string"
+    },
+    "postalCode": {
+      "type": "string"
+    },
+    "city": {
+      "type": "string"
+    },
     "pointId": {
-      "type": "text"
+      "type": "string"
     }
   },
   "data_types": [
@@ -20,8 +35,7 @@
   "screenshots": [],
   "permissions": {
     "accounts": {
-      "type": "io.cozy.accounts",
-      "verbs": ["GET"]
+      "type": "io.cozy.accounts"
     },
     "files": {
       "type": "io.cozy.files"
@@ -67,5 +81,6 @@
       }
     }
   },
-  "manifest_version": "2"
+  "manifest_version": "2",
+  "on_delete_account": "onDeleteAccount.js"
 }
diff --git a/package.json b/package.json
index eb3c5f85ada17a90a7928cd8d91bd1490381b56a..54f2e5454affb2a7a7bd9f34645041b1d3eb6cb9 100644
--- a/package.json
+++ b/package.json
@@ -24,10 +24,15 @@
       "pre-commit": "yarn lint"
     }
   },
+  "jest": {
+    "setupFiles": ["./setupTests.js"]
+  },
   "scripts": {
     "start": "node ./src/index.js",
     "dev": "cozy-konnector-dev",
     "standalone": "cozy-konnector-standalone",
+    "onDeleteAccount:standalone": "cozy-konnector-standalone src/onDeleteAccount.js",
+    "onDeleteAccount": "cozy-konnector-dev src/onDeleteAccount.js",
     "test": "jest",
     "test:cov": "jest --coverage",
     "pretest": "npm run clean",
diff --git a/setupTests.js b/setupTests.js
new file mode 100644
index 0000000000000000000000000000000000000000..fa753e451a24ce4b047c84a8d6b32e33d754e310
--- /dev/null
+++ b/setupTests.js
@@ -0,0 +1,3 @@
+// Disable cozy logger
+const cozyKonnectorsLib = require('cozy-konnector-libs')
+jest.spyOn(cozyKonnectorsLib, 'log').mockImplementation(() => {})
diff --git a/src/core/contractActivation.js b/src/core/contractActivation.js
new file mode 100644
index 0000000000000000000000000000000000000000..a1d05dbc9ccafc4c2a4d71b6f93e11f50d3e9a5e
--- /dev/null
+++ b/src/core/contractActivation.js
@@ -0,0 +1,70 @@
+// @ts-check
+const { log, errors } = require('cozy-konnector-libs')
+const soapRequest = require('easy-soap-request')
+const { parseTags, parseValue, parseServiceId } = require('../helpers/parsing')
+const { commanderCollectePublicationMesures } = require('../requests/sge')
+const xml2js = require('xml2js')
+
+/**
+ * @param {string} url
+ * @param {string} apiAuthKey
+ * @param {string} appLogin
+ * @param {string} name
+ * @param {number} pointId
+ * @param {string} startDate
+ * @param {string} endDate
+ * @return {Promise<number>} User contractId
+ */
+async function activateContract(
+  url,
+  apiAuthKey,
+  appLogin,
+  contractId,
+  name,
+  pointId,
+  startDate,
+  endDate
+) {
+  log('info', 'activateContract')
+  const sgeHeaders = {
+    'Content-Type': 'text/xml;charset=UTF-8',
+    apikey: apiAuthKey,
+  }
+
+  const { response } = await soapRequest({
+    url: `${url}/enedis_SGE_CommandeCollectePublicationMesures/1.0`,
+    headers: sgeHeaders,
+    xml: commanderCollectePublicationMesures(
+      appLogin,
+      contractId,
+      pointId,
+      name,
+      startDate,
+      endDate
+    ),
+  }).catch(err => {
+    log('error', 'commanderCollectePublicationMesures')
+    log('error', err)
+    throw errors.LOGIN_FAILED
+  })
+
+  const parsedReply = await xml2js.parseStringPromise(response.body, {
+    tagNameProcessors: [parseTags],
+    valueProcessors: [parseValue],
+    explicitArray: false,
+  })
+
+  try {
+    return parseServiceId(parsedReply)
+  } catch (error) {
+    log('error', 'Error while activating contract: ' + error)
+    log(
+      'error',
+      `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}`
+    )
+    //TODO: handle SGT4B8: Il existe déjà plusieurs demandes en cours sur le point ?
+    throw errors.LOGIN_FAILED
+  }
+}
+
+module.exports = { activateContract }
diff --git a/src/core/contractStartDate.js b/src/core/contractStartDate.js
new file mode 100644
index 0000000000000000000000000000000000000000..051d4edad9e2d795e056e08c63739fcbd594fc21
--- /dev/null
+++ b/src/core/contractStartDate.js
@@ -0,0 +1,53 @@
+// @ts-check
+const { log, errors } = require('cozy-konnector-libs')
+const soapRequest = require('easy-soap-request')
+const {
+  parseTags,
+  parseValue,
+  parseContractStartDate,
+} = require('../helpers/parsing')
+const xml2js = require('xml2js')
+const { consulterDonneesTechniquesContractuelles } = require('../requests/sge')
+
+/**
+ * Get user contract start date
+ * @param {string} url
+ * @param {string} apiAuthKey
+ * @param {string} userLogin
+ * @param {number} pointId
+ * @returns {Promise<string>}
+ */
+async function getContractStartDate(url, apiAuthKey, userLogin, pointId) {
+  log('info', 'Fetching data start date')
+  const sgeHeaders = {
+    'Content-Type': 'text/xml;charset=UTF-8',
+    apikey: apiAuthKey,
+  }
+
+  const { response } = await soapRequest({
+    url: `${url}/enedis_SGE_ConsultationDonneesTechniquesContractuelles/1.0`,
+    headers: sgeHeaders,
+    xml: consulterDonneesTechniquesContractuelles(pointId, userLogin),
+  }).catch(err => {
+    log('error', 'Error while fetching contract start date : ' + err)
+    throw errors.VENDOR_DOWN
+  })
+
+  const result = await xml2js.parseStringPromise(response.body, {
+    tagNameProcessors: [parseTags],
+    valueProcessors: [parseValue],
+    explicitArray: false,
+  })
+  try {
+    return parseContractStartDate(result)
+  } catch (error) {
+    log('error', 'Error while processing contract start date: ' + error)
+    log(
+      'error',
+      `Enedis issue ${result.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${result.Envelope.Body.Fault.faultstring}`
+    )
+    throw errors.NOT_EXISTING_DIRECTORY
+  }
+}
+
+module.exports = { getContractStartDate }
diff --git a/src/core/contractTermination.js b/src/core/contractTermination.js
new file mode 100644
index 0000000000000000000000000000000000000000..4348e119ee0e3e743d1cee46dcaadcba2eecef17
--- /dev/null
+++ b/src/core/contractTermination.js
@@ -0,0 +1,67 @@
+// @ts-check
+const { log, errors } = require('cozy-konnector-libs')
+const soapRequest = require('easy-soap-request')
+const { parseTags, parseValue } = require('../helpers/parsing')
+const { commanderArretServiceSouscritMesures } = require('../requests/sge')
+const xml2js = require('xml2js')
+
+/**
+ * @param {string} url
+ * @param {string} apiAuthKey
+ * @param {string} appLogin
+ * @param {number} pointId
+ * @param {number} serviceId
+ * @return {Promise<string>} User contractId
+ */
+async function terminateContract(
+  url,
+  apiAuthKey,
+  appLogin,
+  contractId,
+  pointId,
+  serviceId
+) {
+  log('info', 'terminateContract')
+  const sgeHeaders = {
+    'Content-Type': 'text/xml;charset=UTF-8',
+    apikey: apiAuthKey,
+  }
+
+  const { response } = await soapRequest({
+    url: `${url}/enedis_SGE_CommandeArretServiceSouscritMesures/1.0`,
+    headers: sgeHeaders,
+    xml: commanderArretServiceSouscritMesures(
+      appLogin,
+      contractId,
+      pointId,
+      serviceId
+    ),
+  }).catch(err => {
+    log('error', 'commanderArretServiceSouscritMesures')
+    log('error', err)
+    throw errors.VENDOR_DOWN
+  })
+
+  const parsedReply = await xml2js.parseStringPromise(response.body, {
+    tagNameProcessors: [parseTags],
+    valueProcessors: [parseValue],
+    explicitArray: false,
+  })
+
+  try {
+    // We don't need any action on reply for now
+    if (parsedReply.Envelope.Body.Fault) {
+      log(
+        'error',
+        `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}`
+      )
+    }
+    return parsedReply
+  } catch (error) {
+    log('error', 'Error while parsing user contract termination: ' + error)
+    log('error', `Enedis issue ${JSON.stringify(parsedReply.Envelope.Body)}`)
+    throw errors.VENDOR_DOWN
+  }
+}
+
+module.exports = { terminateContract }
diff --git a/src/core/contractVerification.js b/src/core/contractVerification.js
new file mode 100644
index 0000000000000000000000000000000000000000..abc62f013b4ea520e4cd92b80f1fc0cf6a2c435e
--- /dev/null
+++ b/src/core/contractVerification.js
@@ -0,0 +1,64 @@
+// @ts-check
+const { log, errors } = require('cozy-konnector-libs')
+const soapRequest = require('easy-soap-request')
+const { parseTags, parseValue, parseContracts } = require('../helpers/parsing')
+const { rechercherServicesSouscritsMesures } = require('../requests/sge')
+const xml2js = require('xml2js')
+const { contractState, contractLibelle } = require('./types/enum')
+
+/**
+ * @param {string} url
+ * @param {string} apiAuthKey
+ * @param {string} appLogin
+ * @param {number} pointId
+ * @return {Promise<number | null>} User contractId
+ */
+async function verifyContract(url, apiAuthKey, appLogin, contractId, pointId) {
+  log('info', 'verifyContract')
+  const sgeHeaders = {
+    'Content-Type': 'text/xml;charset=UTF-8',
+    apikey: apiAuthKey,
+  }
+
+  const { response } = await soapRequest({
+    url: `${url}/enedis_SGE_RechercheServicesMesures/1.0`,
+    headers: sgeHeaders,
+    xml: rechercherServicesSouscritsMesures(appLogin, contractId, pointId),
+  }).catch(err => {
+    log('error', 'rechercherServicesSouscritsMesures')
+    log('error', err)
+    throw errors.LOGIN_FAILED
+  })
+
+  const parsedReply = await xml2js.parseStringPromise(response.body, {
+    tagNameProcessors: [parseTags],
+    valueProcessors: [parseValue],
+    explicitArray: false,
+  })
+
+  try {
+    const currentContracts = parseContracts(parsedReply)
+    let currentContract = null
+    if (Array.isArray(currentContracts)) {
+      currentContract = parseContracts(parsedReply)[0]
+    } else {
+      currentContract = parseContracts(parsedReply)
+    }
+    if (
+      (currentContract.etatCode === contractState.ACTIF ||
+        currentContract.etatCode === contractState.DEMANDE) &&
+      currentContract.serviceSouscritLibelle === contractLibelle.ACTIF
+    )
+      return currentContract.serviceSouscritId
+    return null
+  } catch (error) {
+    log('error', 'Error while parsing user contract: ' + error)
+    log(
+      'error',
+      `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}`
+    )
+    throw errors.LOGIN_FAILED
+  }
+}
+
+module.exports = { verifyContract }
diff --git a/src/findUserPdl.js b/src/core/findUserPdl.js
similarity index 77%
rename from src/findUserPdl.js
rename to src/core/findUserPdl.js
index ba1871244813edb30b3f7ff343ccbe9cdf19e613..de191fe87554f369bbf4c31ead3cc9393c8185e4 100644
--- a/src/findUserPdl.js
+++ b/src/core/findUserPdl.js
@@ -1,8 +1,8 @@
 // @ts-check
 const { log, errors } = require('cozy-konnector-libs')
 const soapRequest = require('easy-soap-request')
-const { parseUserPdl, parseTags, parseValue } = require('./parsing')
-const { rechercherPoint } = require('./requests/sge')
+const { parseUserPdl, parseTags, parseValue } = require('../helpers/parsing')
+const { rechercherPoint } = require('../requests/sge')
 const xml2js = require('xml2js')
 
 /**
@@ -49,6 +49,11 @@ async function findUserPdl(
   try {
     return parseUserPdl(parsedReply)
   } catch (error) {
+    log('error', 'Error while parsing user PDL: ' + error)
+    log(
+      'error',
+      `Enedis issue ${parsedReply.Envelope.Body.Fault.detail.erreur.resultat.$.code}: ${parsedReply.Envelope.Body.Fault.faultstring}`
+    )
     throw errors.LOGIN_FAILED
   }
 }
diff --git a/src/core/index.js b/src/core/index.js
new file mode 100644
index 0000000000000000000000000000000000000000..e9bf3edd24146cc7d8806a11d55bc6ac0ce24dba
--- /dev/null
+++ b/src/core/index.js
@@ -0,0 +1,15 @@
+const { activateContract } = require('./contractActivation')
+const { getContractStartDate } = require('./contractStartDate')
+const { terminateContract } = require('./contractTermination')
+const { verifyContract } = require('./contractVerification')
+const { findUserPdl } = require('./findUserPdl')
+const { verifyUserIdentity } = require('./verifyUserIdentity')
+
+module.exports = {
+  activateContract,
+  getContractStartDate,
+  terminateContract,
+  verifyContract,
+  findUserPdl,
+  verifyUserIdentity,
+}
diff --git a/src/core/types/enum.js b/src/core/types/enum.js
new file mode 100644
index 0000000000000000000000000000000000000000..485c3f76c0769b016cb906053566b47fd965a1ca
--- /dev/null
+++ b/src/core/types/enum.js
@@ -0,0 +1,22 @@
+/**
+ * Enum for contract-state values.
+ * @readonly
+ * @enum {number}
+ */
+const contractState = {
+  TERMINE: 'TERMINE',
+  ACTIF: 'ACTIF',
+  DEMANDE: 'DEMANDE',
+}
+
+/**
+ * Enum for contractLibelle values.
+ * @readonly
+ * @enum {number}
+ */
+const contractLibelle = {
+  ACTIF:
+    'Collecte de la courbe de charge au pas 30 min avec transmission quotidienne des données brutes en soutirage',
+}
+
+module.exports = { contractState, contractLibelle }
diff --git a/src/core/types/types.js b/src/core/types/types.js
new file mode 100644
index 0000000000000000000000000000000000000000..bcaa2ffef54e0e3c43db9470e735c0323d6c4570
--- /dev/null
+++ b/src/core/types/types.js
@@ -0,0 +1,74 @@
+/**
+ * EnedisKonnectorData definition
+ * @typedef {object} EnedisKonnectorData
+ * @property {number} year
+ * @property {number} month
+ * @property {number} day
+ * @property {number} hour
+ * @property {number} minute
+ */
+
+/**
+ * SGEData definition
+ * @typedef {object} SGEData
+ * @property {number} v
+ * @property {string} d
+ */
+
+/**
+ * Fields definition
+ * @typedef {object} fields
+ * @property {string} wso2BaseUrl
+ * @property {string} apiToken
+ * @property {string} sgeLogin
+ * @property {string} contractId
+ * @property {string} pointId
+ * @property {string} lastname
+ * @property {string} boBaseUrl
+ * @property {string} boToken
+ */
+
+/**
+ * Consent definition
+ * @typedef {object} Consent
+ * @property {number} pointID
+ * @property {string} lastname
+ * @property {string} firstname
+ * @property {string} address
+ * @property {string} postalCode
+ * @property {string} inseeCode
+ * @property {string} endDate
+ * @property {number} [serviceID]
+ * @property {number} [ID]
+ */
+
+/**
+ * User definition
+ * @typedef {object} User
+ * @property {number} pointId
+ * @property {string} lastname
+ * @property {string} firstname
+ * @property {string} postalCode
+ * @property {string} address
+ * @property {string} inseeCode
+ */
+
+/**
+ * Contract definition
+ * @typedef {object} Contract
+ * @property {number} serviceSouscritId
+ * @property {string} pointId
+ * @property {object} serviceSouscritType
+ * @property {string} serviceSouscritLibelle
+ * @property {string} injection
+ * @property {string} soutirage
+ * @property {string} contratId
+ * @property {string} contratLibelle
+ * @property {contractState} etatCode
+ * @property {string} dateDebut
+ * @property {string} dateFin
+ * @property {string} mesuresTypeCode
+ * @property {string} mesuresPas
+ * @property {string} mesuresCorrigees
+ * @property {string} periodiciteTransmission
+ */
diff --git a/src/verifyUserIdentity.js b/src/core/verifyUserIdentity.js
similarity index 53%
rename from src/verifyUserIdentity.js
rename to src/core/verifyUserIdentity.js
index 2d46ceda30cdf1ef223cfbef110b6dbaa6b9d2d5..22a13c3ea6a06471745945b4e4a2e3bd2a8773fe 100644
--- a/src/verifyUserIdentity.js
+++ b/src/core/verifyUserIdentity.js
@@ -1,7 +1,7 @@
 // @ts-check
 const { log, errors } = require('cozy-konnector-libs')
 const { findUserPdl } = require('./findUserPdl')
-const { getInseeCode } = require('./requests/insee')
+const { getInseeCode } = require('../requests/insee')
 
 /**
  * Verify user identity
@@ -9,21 +9,23 @@ const { getInseeCode } = require('./requests/insee')
  * @param {string} baseUrl
  * @param {string} apiAuthKey
  * @param {string} loginUtilisateur
- * @returns {Promise<void>}
+ * @param {boolean} isAlternateStart
+ * @returns {Promise<User>}
  */
 async function verifyUserIdentity(
   fields,
   baseUrl,
   apiAuthKey,
-  loginUtilisateur
+  loginUtilisateur,
+  isAlternateStart = false
 ) {
-  const inseeCode = await getInseeCode(fields.postalCode)
+  const inseeCode = await getInseeCode(fields.postalCode, fields.city)
 
   const pdl = await findUserPdl(
     `${baseUrl}/enedis_SDE_recherche-point/1.0`,
     apiAuthKey,
     loginUtilisateur,
-    fields.name,
+    fields.lastname,
     fields.address,
     fields.postalCode,
     inseeCode
@@ -31,7 +33,20 @@ async function verifyUserIdentity(
 
   if (fields.pointId != pdl) {
     log('error', 'PointId does not match')
-    throw errors.LOGIN_FAILED
+    if (isAlternateStart) {
+      throw errors.TERMS_VERSION_MISMATCH
+    } else {
+      throw errors.LOGIN_FAILED
+    }
+  }
+
+  return {
+    lastname: fields.lastname,
+    firstname: fields.firstname,
+    pointId: fields.pointId,
+    inseeCode,
+    postalCode: fields.postalCode,
+    address: fields.address,
   }
 }
 
diff --git a/src/helpers/account.js b/src/helpers/account.js
new file mode 100644
index 0000000000000000000000000000000000000000..5033e27806739ae46e927b69465f3458441f2552
--- /dev/null
+++ b/src/helpers/account.js
@@ -0,0 +1,46 @@
+const { log } = require('cozy-konnector-libs')
+const { isLocal } = require('./env')
+
+function getAccountId() {
+  log('info', `getAccountId`)
+  try {
+    return JSON.parse(process.env.COZY_FIELDS).account
+  } catch (err) {
+    throw new Error(`You must provide 'account' in COZY_FIELDS: ${err.message}`)
+  }
+}
+
+function getAccountRev() {
+  log('info', `getAccountRev`)
+  try {
+    return isLocal()
+      ? 'fakeAccountRev'
+      : JSON.parse(process.env.COZY_FIELDS).account_rev
+  } catch (err) {
+    throw new Error(`You must provide 'account' in COZY_FIELDS: ${err.message}`)
+  }
+}
+
+/**
+ * Return account secrets.
+ * For local testing, change value with values from your konnector-dev-config.json
+ */
+function getAccountSecret() {
+  try {
+    return isLocal()
+      ? {
+          baseUrl: 'https://test.fr',
+          sgeLogin: 'test@test.com',
+          contractId: '134567',
+          boBaseUrl: 'https://botest.grandlyon.com/',
+          boToken: 'tok31n',
+          apiAuthKey: 'authkeYeasqqd56dsdq',
+        }
+      : JSON.parse(process.env.COZY_PARAMETERS).secret
+  } catch (err) {
+    throw new Error(
+      `You must provide 'account-types' in COZY_PARAMETERS: ${err.message}`
+    )
+  }
+}
+module.exports = { getAccountId, getAccountRev, getAccountSecret }
diff --git a/src/aggregate.js b/src/helpers/aggregate.js
similarity index 100%
rename from src/aggregate.js
rename to src/helpers/aggregate.js
diff --git a/src/helpers/env.js b/src/helpers/env.js
new file mode 100644
index 0000000000000000000000000000000000000000..07df4c667829ca46efa56b9dfb23e1f1b93b3b53
--- /dev/null
+++ b/src/helpers/env.js
@@ -0,0 +1,9 @@
+function isLocal() {
+  return (
+    process.env.NODE_ENV === 'development' ||
+    process.env.NODE_ENV === 'local' ||
+    process.env.NODE_ENV === 'standalone'
+  )
+}
+
+module.exports = { isLocal }
diff --git a/src/parsing.js b/src/helpers/parsing.js
similarity index 71%
rename from src/parsing.js
rename to src/helpers/parsing.js
index 05439e132dbcf03fbb96462b38e16e5b23c032f4..a1f9e8ff3669f1823a252557cae16b5770c169a9 100644
--- a/src/parsing.js
+++ b/src/helpers/parsing.js
@@ -16,12 +16,12 @@ function parseUserPdl(result) {
 }
 
 /**
- * Return start date
+ * Return User contract start date
  * @param {string} result
  * @returns {string}
  */
-function parseSgeXmlTechnicalData(result) {
-  log('info', 'Parsing technical data')
+function parseContractStartDate(result) {
+  log('info', 'Parsing contract start date')
   const json = JSON.stringify(result)
   return JSON.parse(json)['Envelope']['Body'][
     'consulterDonneesTechniquesContractuellesResponse'
@@ -30,6 +30,32 @@ function parseSgeXmlTechnicalData(result) {
   ]
 }
 
+/**
+ * Return User contract start date
+ * @param {string} result
+ * @returns {Contract[] | Contract}
+ */
+function parseContracts(result) {
+  log('info', 'Parsing contract')
+  const json = JSON.stringify(result)
+  return JSON.parse(json)['Envelope']['Body'][
+    'rechercherServicesSouscritsMesuresResponse'
+  ]['servicesSouscritsMesures']['serviceSouscritMesures']
+}
+
+/**
+ * Return User contract start date
+ * @param {string} result
+ * @returns {number}
+ */
+function parseServiceId(result) {
+  log('info', 'Parsing serviceId')
+  const json = JSON.stringify(result)
+  return JSON.parse(json)['Envelope']['Body'][
+    'commanderCollectePublicationMesuresResponse'
+  ]['serviceSouscritId']
+}
+
 /**
  * Parsing SGE xml reply to get only mesure data
  * @param {string} result
@@ -91,9 +117,11 @@ function parseValue(value, name) {
 
 module.exports = {
   parseSgeXmlData,
-  parseSgeXmlTechnicalData,
   formateDataForDoctype,
   parseTags,
   parseValue,
   parseUserPdl,
+  parseContracts,
+  parseContractStartDate,
+  parseServiceId,
 }
diff --git a/src/index.js b/src/index.js
index 20790eeda46e1e5895a2ce5dcfb0cd9171eecd5b..4c3c65281bb5cf4d92b4d424d42c4df64f121d86 100644
--- a/src/index.js
+++ b/src/index.js
@@ -10,21 +10,16 @@ const soapRequest = require('easy-soap-request')
 const moment = require('moment')
 require('moment-timezone')
 const xml2js = require('xml2js')
-const { buildAgregatedData } = require('./aggregate')
+const { buildAgregatedData } = require('./helpers/aggregate')
 const {
   parseSgeXmlData,
-  parseSgeXmlTechnicalData,
   formateDataForDoctype,
   parseTags,
   parseValue,
-} = require('./parsing')
+} = require('./helpers/parsing')
 const {
-  consulterDonneesTechniquesContractuelles,
   consultationMesuresDetailleesMaxPower,
   consultationMesuresDetaillees,
-
-  commanderCollectePublicationMesures,
-  commanderArretServiceSouscritMesures,
 } = require('./requests/sge')
 const {
   updateBoConsent,
@@ -32,7 +27,15 @@ const {
   getBoConsent,
   deleteBoConsent,
 } = require('./requests/bo')
-const { verifyUserIdentity } = require('./verifyUserIdentity')
+const {
+  verifyUserIdentity,
+  activateContract,
+  verifyContract,
+  terminateContract,
+  getContractStartDate,
+} = require('./core')
+const { getAccount, saveAccountData } = require('./requests/cozy')
+const { isLocal } = require('./helpers/env')
 
 moment.locale('fr') // set the language
 moment.tz.setDefault('Europe/Paris') // set the timezone
@@ -47,26 +50,50 @@ let startDailyDateString = startDailyDate.format('YYYY-MM-DD')
 const startLoadDate = moment().subtract(7, 'day')
 const endDate = moment()
 const endDateString = endDate.format('YYYY-MM-DD')
+const ACCOUNT_ID = isLocal() ? 'default_account_id' : 'enedis-sge-grandlyon'
 
 module.exports = new BaseKonnector(start)
 
-// The start function is run by the BaseKonnector instance only when it got all the account
-// information (fields). When you run this connector yourself in "standalone" mode or "dev" mode,
-// the account information come from ./konnector-dev-config.json file
-// cozyParameters are static parameters, independents from the account. Most often, it can be a
-// secret api key.
+/**
+ * The start function is run by the BaseKonnector instance only when it got all the account
+ * information (fields). When you run this connector yourself in "standalone" mode or "dev" mode,
+ * the account information come from ./konnector-dev-config.json file
+ * cozyParameters are static parameters, independents from the account. Most often, it can be a
+ * secret api key.
+ * @param {fields} fields
+ * @param {{secret: fields}} cozyParameters
+ */
 async function start(fields, cozyParameters) {
-  log('info', 'Gathering data ...')
+  log('info', 'Konnector configuration ...')
+
+  const pointId = parseInt(fields.pointId)
   let baseUrl = fields.wso2BaseUrl
   let apiAuthKey = fields.apiToken
-  let loginUtilisateur = fields.loginUtilisateur
-  log('info', 'Authenticating ...')
-  //TODO: Verify if condition is working in local and on build version
+  let contractId = fields.contractId
+  let sgeLogin = fields.sgeLogin
+  let boToken = fields.boToken
+  let boBaseUrl = fields.boBaseUrl
   if (cozyParameters && Object.keys(cozyParameters).length !== 0) {
     log('debug', 'Found COZY_PARAMETERS')
     baseUrl = cozyParameters.secret.wso2BaseUrl
     apiAuthKey = cozyParameters.secret.apiToken
-    loginUtilisateur = cozyParameters.secret.loginUtilisateur
+    contractId = cozyParameters.secret.contractId
+    sgeLogin = cozyParameters.secret.sgeLogin
+    boBaseUrl = cozyParameters.secret.boBaseUrl
+    boToken = cozyParameters.secret.boToken
+  }
+
+  // Prevent missing configuration
+  if (
+    !baseUrl ||
+    !apiAuthKey ||
+    !contractId ||
+    !sgeLogin ||
+    !boToken ||
+    !boBaseUrl
+  ) {
+    log('error', `Missing configuration secrets`)
+    throw errors.VENDOR_DOWN
   }
 
   /**
@@ -79,104 +106,183 @@ async function start(fields, cozyParameters) {
    */
   log('info', 'User Logging...')
 
-  if (await isFirstStart()) {
-    await verifyUserIdentity(fields, baseUrl, apiAuthKey, loginUtilisateur)
-
-    await createBoConsent()
-    //TODO: remove because useless ? Done later in code
-    // const startDate = await getDataStartDate(
-    //   baseUrl,
-    //   apiAuthKey,
-    //   loginUtilisateur,
-    //   fields.pointId
-    // )
-    await commanderCollectePublicationMesures()
-    await updateBoConsent()
+  if (isFirstStart(await getAccount(ACCOUNT_ID))) {
+    const user = await verifyUserIdentity(fields, baseUrl, apiAuthKey, sgeLogin)
+
+    let consent = await createBoConsent(
+      boBaseUrl,
+      boToken,
+      pointId,
+      user.lastname,
+      user.firstname,
+      user.address,
+      user.postalCode,
+      user.inseeCode
+    )
+
+    // handle user contract start date in order to preperly request data
+    const userContractstartDate = await getContractStartDate(
+      baseUrl,
+      apiAuthKey,
+      sgeLogin,
+      pointId
+    )
+    startDailyDate = moment(userContractstartDate, 'YYYY-MM-DD')
+    startDailyDateString = startDailyDate.format('YYYY-MM-DD')
+
+    const contractStartDate = moment().format('YYYY-MM-DD')
+    const contractEndDate = moment()
+      .add(1, 'year') // SGE force 1 year duration
+      .format('YYYY-MM-DD')
+
+    let serviceId = await verifyContract(
+      baseUrl,
+      apiAuthKey,
+      sgeLogin,
+      contractId,
+      user.pointId
+    )
+    if (!serviceId) {
+      serviceId = await activateContract(
+        baseUrl,
+        apiAuthKey,
+        sgeLogin,
+        contractId,
+        user.lastname,
+        user.pointId,
+        contractStartDate,
+        contractEndDate
+      )
+    }
+    consent = await updateBoConsent(
+      boBaseUrl,
+      boToken,
+      consent,
+      serviceId.toString()
+    )
+    // Save bo id into account
+    const accountData = await getAccount(ACCOUNT_ID)
+
+    await saveAccountData(this.accountId, {
+      ...accountData.data,
+      consentId: consent.ID,
+    })
   } else {
-    //AlternateStart
-    await getBoConsent()
-    if (!(await verifyUserIdentity(fields))) {
-      await deleteBoConsent()
-      await commanderArretServiceSouscritMesures()
-      throw errors.TERMS_VERSION_MISMATCH
+    // AlternateStart
+    const accountData = await getAccount(ACCOUNT_ID)
+    const userConsent = await getBoConsent(
+      boBaseUrl,
+      boToken,
+      accountData.data.consentId
+    )
+    const user = await verifyUserIdentity(
+      fields,
+      baseUrl,
+      apiAuthKey,
+      sgeLogin,
+      true
+    )
+
+    if (!userConsent) {
+      log('error', 'No user consent found')
+      throw errors.VENDOR_DOWN
+    }
+
+    const consentEndDate = Date.parse(userConsent.endDate)
+    const today = Date.now()
+    if (
+      user.lastname.toLocaleUpperCase() !==
+        userConsent.lastname.toLocaleUpperCase() ||
+      !user ||
+      consentEndDate < today
+    ) {
+      await deleteConsent(
+        userConsent,
+        baseUrl,
+        apiAuthKey,
+        sgeLogin,
+        contractId,
+        pointId,
+        boBaseUrl,
+        boToken
+      )
     }
   }
   log('info', 'Successfully logged in')
 
-  await gatherData(baseUrl, apiAuthKey, loginUtilisateur, fields.pointId)
+  await gatherData(baseUrl, apiAuthKey, sgeLogin, pointId)
+}
+
+/**
+ * Delete User Consent
+ * @param {Consent} userConsent
+ * @param {string} baseUrl
+ * @param {string} apiAuthKey
+ * @param {string} sgeLogin
+ * @param {string} contractId
+ * @param {number} pointId
+ * @param {string} boBaseUrl
+ * @param {string} boToken
+ */
+async function deleteConsent(
+  userConsent,
+  baseUrl,
+  apiAuthKey,
+  sgeLogin,
+  contractId,
+  pointId,
+  boBaseUrl,
+  boToken
+) {
+  log('error', `Invalid or not found consent for user`)
+  if (userConsent.serviceID) {
+    await terminateContract(
+      baseUrl,
+      apiAuthKey,
+      sgeLogin,
+      contractId,
+      pointId,
+      userConsent.serviceID
+    )
+    await deleteBoConsent(boBaseUrl, boToken, userConsent.ID || 0)
+  } else {
+    log('error', `No service id retrieved from BO`)
+    throw errors.VENDOR_DOWN
+  }
+  throw errors.TERMS_VERSION_MISMATCH
 }
 
 /**
  * Main method for gathering data
  * @param {string} baseUrl
  * @param {string} apiAuthKey
- * @param {string} loginUtilisateur
+ * @param {string} sgeLogin
  * @param {number} pointId
  */
-async function gatherData(baseUrl, apiAuthKey, loginUtilisateur, pointId) {
+async function gatherData(baseUrl, apiAuthKey, sgeLogin, pointId) {
   log('info', 'Querying data...')
-  await getDataStartDate(
-    `${baseUrl}/enedis_SGE_ConsultationDonneesTechniquesContractuelles/1.0`,
-    apiAuthKey,
-    loginUtilisateur,
-    pointId
-  )
+  await getContractStartDate(baseUrl, apiAuthKey, sgeLogin, pointId)
   await getData(
     `${baseUrl}/enedis_SGE_ConsultationMesuresDetaillees/1.0`,
     apiAuthKey,
-    loginUtilisateur,
+    sgeLogin,
     pointId
   )
   await getMaxPowerData(
     `${baseUrl}/enedis_SGE_ConsultationMesuresDetaillees/1.0`,
     apiAuthKey,
-    loginUtilisateur,
+    sgeLogin,
     pointId
   )
   await getDataHalfHour(
     `${baseUrl}/enedis_SGE_ConsultationMesuresDetaillees/1.0`,
     apiAuthKey,
-    loginUtilisateur,
+    sgeLogin,
     pointId
   )
   log('info', 'Querying data: done')
 }
 
-/**
- *
- * @param {string} url
- * @param {string} apiAuthKey
- * @param {string} userLogin
- * @param {number} pointId
- */
-async function getDataStartDate(url, apiAuthKey, userLogin, pointId) {
-  log('info', 'Fetching data start date')
-  const sgeHeaders = {
-    'Content-Type': 'text/xml;charset=UTF-8',
-    apikey: apiAuthKey,
-  }
-
-  const { response } = await soapRequest({
-    url: url,
-    headers: sgeHeaders,
-    xml: consulterDonneesTechniquesContractuelles(pointId, userLogin),
-  }).catch(err => {
-    log('error', 'technicalDataResponse')
-    log('error', err)
-    return err
-  })
-
-  xml2js.parseString(
-    response.body,
-    {
-      tagNameProcessors: [parseTags],
-      valueProcessors: [parseValue],
-      explicitArray: false,
-    },
-    processStartDate()
-  )
-}
-
 /**
  * Get hour data
  * @param {string} url
@@ -305,6 +411,7 @@ async function getDataHalfHour(url, apiAuthKey, userLogin, pointId) {
     const incrementedEndDateString = moment(endDate)
       .subtract(7 * i, 'day')
       .format('YYYY-MM-DD')
+
     const { response } = await soapRequest({
       url: url,
       headers: sgeHeaders,
@@ -346,38 +453,29 @@ function processData(doctype = 'com.grandlyon.enedis.day') {
       throw err
     }
     // Return only needed part of info
-    const data = parseSgeXmlData(result)
-    const processedDailyData = await storeData(
-      await formateDataForDoctype(data),
-      doctype,
-      ['year', 'month', 'day', 'hour', 'minute']
-    )
-
-    log('info', 'Agregate enedis daily data for month and year')
-    if (doctype === 'com.grandlyon.enedis.day') {
-      log('info', 'Agregating...')
-      await agregateMonthAndYearData(processedDailyData)
-    }
-  }
-}
-
-/**
- * Store an accurate start date based on contrat start
- */
-function processStartDate() {
-  return async (err, result) => {
-    if (err) {
-      log('error', err)
-      throw err
-    }
-    // update start Date with contract openning date
+    log('info', doctype)
     try {
-      startDailyDate = moment(parseSgeXmlTechnicalData(result), 'YYYY-MM-DD')
-      startDailyDateString = startDailyDate.format('YYYY-MM-DD')
-    } catch (err) {
-      log('error', err)
-      //TODO: custom error ?
-      throw err
+      const data = parseSgeXmlData(result)
+      const processedDailyData = await storeData(
+        await formateDataForDoctype(data),
+        doctype,
+        ['year', 'month', 'day', 'hour', 'minute']
+      )
+
+      log('info', 'Agregate enedis daily data for month and year')
+      if (doctype === 'com.grandlyon.enedis.day') {
+        log('info', 'Agregating...')
+        await agregateMonthAndYearData(processedDailyData)
+      }
+    } catch (e) {
+      if (doctype === 'com.grandlyon.enedis.minute') {
+        log(
+          'warn',
+          `No half-hour activated. Issue: ${result.Envelope.Body.Fault.faultstring}`
+        )
+      } else {
+        log('error', `Unkown error ${e}`)
+      }
     }
   }
 }
@@ -435,8 +533,11 @@ async function agregateMonthAndYearData(data) {
 /**
  * @returns {boolean}
  */
-function isFirstStart() {
-  console.log('isFirstStart')
-  //TODO: Implement
+function isFirstStart(account) {
+  if (account?.data?.consentId) {
+    log('info', 'Konnector not first start')
+    return false
+  }
+  log('info', 'Konnector first start')
   return true
 }
diff --git a/src/onDeleteAccount.js b/src/onDeleteAccount.js
new file mode 100644
index 0000000000000000000000000000000000000000..cbf7f99a89162e56db32aa81d9c493530c7deff1
--- /dev/null
+++ b/src/onDeleteAccount.js
@@ -0,0 +1,74 @@
+// @ts-check
+const { log, errors } = require('cozy-konnector-libs')
+const { getAccountRev, getAccountSecret } = require('./helpers/account')
+const { getBoConsent, deleteBoConsent } = require('./requests/bo')
+const { terminateContract } = require('./core/contractTermination')
+const { getAccount } = require('./requests/cozy')
+const moment = require('moment')
+require('moment-timezone')
+moment.locale('fr') // set the language
+moment.tz.setDefault('Europe/Paris') // set the timezone
+const { isLocal } = require('./helpers/env')
+const ACCOUNT_ID = isLocal() ? 'default_account_id' : 'enedis-sge-grandlyon'
+
+async function onDeleteAccount() {
+  log('info', 'Deleting account ...')
+  log('info', 'Getting secrets ...')
+  const secrets = getAccountSecret()
+  const accountRev = getAccountRev()
+
+  if (accountRev) {
+    log('info', 'Account rev exist')
+    const accountData = await getAccount(ACCOUNT_ID)
+    const userConsent = await getBoConsent(
+      secrets.boBaseUrl,
+      secrets.boToken,
+      accountData.data.consentId
+    )
+
+    if (userConsent.ID && userConsent.pointID) {
+      log('log', `Consent ${userConsent.ID} found for user`)
+      if (userConsent.serviceID) {
+        await deleteBoConsent(
+          secrets.boBaseUrl,
+          secrets.boToken,
+          userConsent.ID
+        )
+        await terminateContract(
+          secrets.baseUrl,
+          secrets.apiAuthKey,
+          secrets.sgeLogin,
+          secrets.contractId,
+          userConsent.pointID,
+          userConsent.serviceID
+        )
+      } else {
+        log('error', `No service id retrieved from BO`)
+        throw errors.VENDOR_DOWN
+      }
+    }
+
+    log('info', 'Deleting account succeed')
+  } else {
+    log(
+      'error',
+      'No account revision was found, something went wrong during the deletion of said account'
+    )
+    throw errors.VENDOR_DOWN
+  }
+}
+
+onDeleteAccount().then(
+  () => {
+    log('info', `onDeleteAccount: Successfully delete consent and account.`)
+  },
+  err => {
+    log(
+      'error',
+      `onDeleteAccount: An error occured during script: ${err.message}`
+    )
+    throw errors.VENDOR_DOWN
+  }
+)
+
+module.exports = { onDeleteAccount }
diff --git a/src/requests/bo.js b/src/requests/bo.js
index 53323c123d8891b0d6c9592486072ece1cec4cbf..69ebcadb091a9721a987734268e56fbbe1a24fa2 100644
--- a/src/requests/bo.js
+++ b/src/requests/bo.js
@@ -1,39 +1,129 @@
 // @ts-check
-const { log } = require('cozy-konnector-libs')
+const { log, errors } = require('cozy-konnector-libs')
+const { default: axios } = require('axios')
 
 /**
- *
+ * @param {number} pointID
+ * @param {string} lastname
+ * @param {string} firstname
+ * @param {string} address
+ * @param {string} postalCode
+ * @param {string} inseeCode
+ * @returns {Promise<Consent>}
  */
-function createBoConsent() {
-  //TODO: Implement
+async function createBoConsent(
+  url,
+  token,
+  pointID,
+  lastname,
+  firstname,
+  address,
+  postalCode,
+  inseeCode
+) {
   log('info', `Query createBoConsent`)
-  throw new Error('Function not implemented.')
+  const headers = {
+    headers: {
+      Authorization: `Bearer ${token}`,
+    },
+  }
+
+  try {
+    const { data } = await axios.post(
+      `${url}/consent`,
+      {
+        pointID,
+        lastname,
+        firstname,
+        address,
+        postalCode,
+        inseeCode,
+      },
+      headers
+    )
+    return data
+  } catch (e) {
+    log('error', `BO replied with ${e}`)
+    throw errors.MAINTENANCE
+  }
 }
 
 /**
- *
+ * @param {string} url
+ * @param {string} token
+ * @param {Consent} consent
+ * @param {string} serviceId
+ * @returns {Promise<Consent>}
  */
-function updateBoConsent() {
-  //TODO: Implement
+async function updateBoConsent(url, token, consent, serviceId) {
   log('info', `Query updateBoConsent`)
-  throw new Error('Function not implemented.')
+  const headers = {
+    headers: {
+      Authorization: `Bearer ${token}`,
+    },
+  }
+
+  try {
+    let consentId = ''
+    if (consent.ID) {
+      consentId = consent.ID.toString()
+    }
+    const { data } = await axios.put(
+      `${url}/consent/${consentId}`,
+      {
+        ...consent,
+        serviceId: parseInt(serviceId),
+      },
+      headers
+    )
+    return data
+  } catch (e) {
+    log('error', `BO replied with ${e}`)
+    throw errors.MAINTENANCE
+  }
 }
 
 /**
- *
+ * @param {number} boId
+ * @returns {Promise<Consent>}
  */
-function getBoConsent() {
-  //TODO: Implement
-  log('info', `Query getBoConsent`)
-  throw new Error('Function not implemented.')
+async function getBoConsent(url, token, boId) {
+  log('info', `Query getBoConsent ${boId}`)
+  const headers = {
+    headers: {
+      Authorization: `Bearer ${token}`,
+    },
+  }
+  try {
+    const { data } = await axios.get(`${url}/consent/${boId}`, headers)
+    return data
+  } catch (e) {
+    log('error', `BO replied with ${e}`)
+    throw errors.MAINTENANCE
+  }
 }
+
 /**
- *
+ * Delete BO consent
+ * @param {string} url
+ * @param {string} token
+ * @param {number} boId
+ * @returns
  */
-function deleteBoConsent() {
-  //TODO: deleteBoConsent
-  log('info', `Query createBoConsent`)
-  throw new Error('Function not implemented.')
+async function deleteBoConsent(url, token, boId) {
+  log('info', `Query deleteBoConsent ${boId}`)
+  const headers = {
+    headers: {
+      Authorization: `Bearer ${token}`,
+    },
+  }
+  try {
+    const { data } = await axios.delete(`${url}/consent/${boId}`, headers)
+    return data
+  } catch (e) {
+    log('error', `BO replied with ${e}`)
+    throw errors.MAINTENANCE
+  }
 }
 
 module.exports = {
diff --git a/src/requests/cozy.js b/src/requests/cozy.js
new file mode 100644
index 0000000000000000000000000000000000000000..138c822a8de790c029b1879ae59bbdca053d151d
--- /dev/null
+++ b/src/requests/cozy.js
@@ -0,0 +1,25 @@
+const { log, updateOrCreate } = require('cozy-konnector-libs')
+const { isLocal } = require('../helpers/env')
+const cozyClient = require('cozy-konnector-libs/dist/libs/cozyclient')
+
+async function saveAccountData(accountId, accountData) {
+  log('info', `saveAccountData: ${accountId}`)
+
+  let account = await getAccount(accountId)
+
+  account = await updateOrCreate(
+    [{ ...account, data: accountData }],
+    'io.cozy.accounts'
+  )
+  return account
+}
+
+async function getAccount(accountId) {
+  log('info', `getAccount: ${accountId}`)
+  const accounts = await cozyClient.data.findAll('io.cozy.accounts')
+  return accounts.filter(account =>
+    isLocal() ? account._id === accountId : account.account_type === accountId
+  )[0]
+}
+
+module.exports = { getAccount, saveAccountData }
diff --git a/src/requests/sge.js b/src/requests/sge.js
index 22669bdcb1f4fe6dc9b1b083da64cb6f8b213fbe..518c624b5d2136bff45fef03e22d96accbc0e137 100644
--- a/src/requests/sge.js
+++ b/src/requests/sge.js
@@ -133,7 +133,6 @@ function rechercherPoint(appLogin, name, postalCode, inseeCode, address) {
     'info',
     `Query rechercherPoint - postal code / insee code: ${postalCode} / ${inseeCode}`
   )
-  //TODO: handle address
   return `<?xml version='1.0' encoding='utf-8'?>
   <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
      xmlns:v2="http://www.enedis.fr/sge/b2b/services/rechercherpoint/v2.0"
@@ -160,7 +159,7 @@ function rechercherPoint(appLogin, name, postalCode, inseeCode, address) {
  * Search if user as a service
  * @param {string} appLogin
  * @param {string} contractId
- * @param {string} pointId
+ * @param {number} pointId
  * @returns {*}
  */
 function rechercherServicesSouscritsMesures(appLogin, contractId, pointId) {
@@ -186,7 +185,7 @@ function rechercherServicesSouscritsMesures(appLogin, contractId, pointId) {
  * Activate half hour data collect for user
  * @param {string} appLogin
  * @param {string} contractId
- * @param {string} pointId
+ * @param {number} pointId
  * @param {string} name
  * @param {string} startDate
  * @param {string} endDate
@@ -245,8 +244,8 @@ function commanderCollectePublicationMesures(
  * Stop the user consent
  * @param {string} appLogin
  * @param {string} contractId
- * @param {string} pointId
- * @param {string} serviceSouscritId
+ * @param {number} pointId
+ * @param {number} serviceSouscritId
  * @returns {*}
  */
 function commanderArretServiceSouscritMesures(
diff --git a/src/types.js b/src/types.js
deleted file mode 100644
index b5cff384d39d1698486456f6abbf49fce321ca55..0000000000000000000000000000000000000000
--- a/src/types.js
+++ /dev/null
@@ -1,38 +0,0 @@
-/**
- * EnedisKonnectorData definition
- * @typedef {object} EnedisKonnectorData
- * @property {number} year
- * @property {number} month
- * @property {number} day
- * @property {number} hour
- * @property {number} minute
- */
-
-/**
- * SGEData definition
- * @typedef {object} SGEData
- * @property {number} v
- * @property {string} d
- */
-
-// /**
-//  * User definition
-//  * @typedef {object} User
-//  * @property {string} name
-//  * @property {string} address
-//  * @property {string} postalCode
-//  * @property {string} pointId
-//  * @property {string} [inseeCode]
-//  */
-
-/**
- * Consent definition
- * @typedef {object} Consent
- * @property {number} pointId
- * @property {string} name
- * @property {string} adresse
- * @property {string} postalCode
- * @property {string} inseeCode
- * @property {string} [serviceId]
- * @property {number} [id]
- */
diff --git a/webpack.config.js b/webpack.config.js
index e60d80f45c206a0e2888cbc79899add29262d6a6..d9ed003f4608ce3303678228355114cb9a14d7ce 100644
--- a/webpack.config.js
+++ b/webpack.config.js
@@ -4,7 +4,7 @@ const webpack = require('webpack')
 const fs = require('fs')
 const SvgoInstance = require('svgo')
 
-const entry = require('./package.json').main
+const index = require('./package.json').main
 
 const readManifest = () =>
   JSON.parse(fs.readFileSync(path.join(__dirname, './manifest.konnector')))
@@ -28,12 +28,15 @@ try {
 const appIconRX = iconName && new RegExp(`[^/]*/${iconName}`)
 
 module.exports = {
-  entry,
+  entry: {
+    index,
+    onDeleteAccount: './src/onDeleteAccount.js',
+  },
   target: 'node',
   mode: 'none',
   output: {
     path: path.join(__dirname, 'build'),
-    filename: 'index.js',
+    filename: '[name].js',
   },
   plugins: [
     new CopyPlugin({