diff --git a/src/core/core.js b/src/core/core.js
new file mode 100644
index 0000000000000000000000000000000000000000..8c4e97e62ad5c4e64f25a953cb81686d6a459566
--- /dev/null
+++ b/src/core/core.js
@@ -0,0 +1,132 @@
+// @ts-check
+
+const { log, errors } = require('cozy-konnector-libs')
+const { getAccount, saveAccountData } = require('../requests/cozy')
+const { deleteBoConsent, createBoConsent } = require('../requests/bo')
+const moment = require('moment')
+const { isLocal } = require('../helpers/env')
+const { createGRDFConsent } = require('../requests/grdf')
+require('moment-timezone')
+moment.locale('fr') // set the language
+moment.tz.setDefault('Europe/Paris') // set the timezone
+
+const ACCOUNT_ID = isLocal() ? 'default_account_id' : 'grdfgrandlyon'
+const manualExecution = process.env.COZY_JOB_MANUAL_EXECUTION === 'true'
+
+/**
+ * @param {GRDFConsent[]} consents
+ * @param {string} boBaseUrl
+ * @param {string} boToken
+ * @returns {Promise<boolean>} Returns true if consent needs to be created. Returns false if consent is valid
+ */
+async function handleConsents(consents, boBaseUrl, boToken) {
+  if (consents.some(consent => consent.etat_droit_acces === 'Active')) {
+    log('info', 'Found consent "Active"')
+    return false
+  }
+  if (consents.some(consent => consent.etat_droit_acces === 'A valider')) {
+    log('info', 'Found consent "A valider"')
+    throw errors.CHALLENGE_ASKED
+  }
+  if (consents.some(consent => consent.etat_droit_acces === 'Révoquée')) {
+    log('info', 'Found consent "Révoquée"')
+    throw errors.USER_ACTION_NEEDED_ACCOUNT_REMOVED
+  }
+
+  // Check if daily check & if obsolete consent is found, continue otherwise
+  if (
+    !manualExecution &&
+    consents.some(consent => consent.etat_droit_acces === 'Obsolète')
+  ) {
+    log('info', 'Found consent "Obsolète"')
+  }
+
+  if (consents.some(consent => consent.etat_droit_acces === 'A revérifier')) {
+    log('info', 'Found consent "A revérifier"')
+    throw errors.VENDOR_DOWN
+  }
+
+  if (consents.some(consent => consent.etat_droit_acces === 'Refusée')) {
+    log('info', 'Found consent "Refusée"')
+    const accountData = await getAccount(ACCOUNT_ID)
+    if (accountData?.data?.consentId) {
+      await deleteBoConsent({
+        boBaseUrl,
+        boToken,
+        consentId: accountData.data.consentId
+      })
+      delete accountData.data.consentId
+      await saveAccountData(accountData)
+    }
+    if (!manualExecution) {
+      throw errors.USER_ACTION_NEEDED_SCA_REQUIRED
+    }
+  }
+
+  // "message_retour_traitement": "Aucun droit d’accès trouvé." OU Obsolète -> create consent
+  return true
+}
+
+/**
+ * Creates consents
+ * - first in our back-office
+ * - then at GRDF
+ * @returns {Promise<boolean>} isWaitingForConsentValidation Boolean that indicates that the consent was created and needs a user validation.
+ */
+async function createConsent({
+  bearerToken,
+  pce,
+  email,
+  firstname,
+  lastname,
+  postalCode,
+  startDate,
+  endDate,
+  boToken,
+  boBaseUrl
+}) {
+  const startDateString = moment(startDate).format('YYYY-MM-DD')
+  const endDateConsent = moment(endDate).add(1, 'year')
+  const endDateString = endDateConsent.format('YYYY-MM-DD')
+
+  const { ID: consentId } = await createBoConsent({
+    boBaseUrl,
+    boToken,
+    pce,
+    firstname,
+    lastname,
+    postalCode,
+    endDate: endDateConsent
+  }).catch(err => {
+    log('error', `Failed to create BO consent, ${err}`)
+    throw errors.MAINTENANCE
+  })
+
+  // Save BO consentId into account
+  const accountData = await getAccount(ACCOUNT_ID)
+  await saveAccountData(ACCOUNT_ID, {
+    ...accountData.data,
+    consentId: consentId
+  })
+
+  await createGRDFConsent({
+    bearerToken,
+    email,
+    lastname,
+    pce,
+    postalCode,
+    startDate: startDateString,
+    endDate: endDateString
+  }).catch(async err => {
+    await deleteBoConsent({
+      boBaseUrl,
+      boToken,
+      consentId: consentId
+    })
+    throw err
+  })
+
+  return true
+}
+
+module.exports = { handleConsents, createConsent }
diff --git a/src/index.js b/src/index.js
index 4be61f35df6b5e61eca614e0b38e5898ae17ccb6..e52f5f4274449a82ab50b55194527c30bb835494 100755
--- a/src/index.js
+++ b/src/index.js
@@ -8,7 +8,7 @@ const {
   log
 } = require('cozy-konnector-libs')
 const getDataGenericErrors = require('./helpers/getDataGenericErrors')
-const { isDev, isLocal } = require('./helpers/env')
+const { isDev } = require('./helpers/env')
 const moment = require('moment')
 require('moment-timezone')
 moment.locale('fr') // set the language
@@ -17,13 +17,8 @@ const Sentry = require('@sentry/node')
 // eslint-disable-next-line
 const Tracing = require('@sentry/tracing') // Needed for tracking performance in Sentry
 const { version } = require('../package.json')
-const { createBoConsent, deleteBoConsent } = require('./requests/bo')
-const {
-  createGRDFConsent,
-  getAuthToken,
-  getConsents
-} = require('./requests/grdf')
-const { getAccount, saveAccountData } = require('./requests/cozy')
+const { getAuthToken, getConsents } = require('./requests/grdf')
+const { handleConsents, createConsent } = require('./core/core')
 
 Sentry.init({
   dsn:
@@ -49,126 +44,8 @@ const manualExecution = process.env.COZY_JOB_MANUAL_EXECUTION === 'true'
 const startDate = moment().subtract(manualExecution ? 1 : 3, 'year')
 const endDate = moment().startOf('day')
 
-const ACCOUNT_ID = isLocal() ? 'default_account_id' : 'grdfgrandlyon'
-
 module.exports = new BaseKonnector(start)
 
-/**
- * @param {GRDFConsent[]} consents
- * @param {string} boBaseUrl
- * @param {string} boToken
- * @returns {Promise<boolean>} Returns true if consent needs to be created. Returns false if consent is valid
- */
-async function handleConsents(consents, boBaseUrl, boToken) {
-  if (consents.some(consent => consent.etat_droit_acces === 'Active')) {
-    log('info', 'Found consent "Active"')
-    return false
-  }
-  if (consents.some(consent => consent.etat_droit_acces === 'A valider')) {
-    log('info', 'Found consent "A valider"')
-    throw errors.CHALLENGE_ASKED
-  }
-  if (consents.some(consent => consent.etat_droit_acces === 'Révoquée')) {
-    log('info', 'Found consent "Révoquée"')
-    throw errors.USER_ACTION_NEEDED_ACCOUNT_REMOVED
-  }
-
-  // Check if daily check & if obsolete consent is found, continue otherwise
-  if (
-    !manualExecution &&
-    consents.some(consent => consent.etat_droit_acces === 'Obsolète')
-  ) {
-    log('info', 'Found consent "Obsolète"')
-  }
-
-  if (consents.some(consent => consent.etat_droit_acces === 'A revérifier')) {
-    log('info', 'Found consent "A revérifier"')
-    throw errors.VENDOR_DOWN
-  }
-
-  if (consents.some(consent => consent.etat_droit_acces === 'Refusée')) {
-    log('info', 'Found consent "Refusée"')
-    const accountData = await getAccount(ACCOUNT_ID)
-    if (accountData?.data?.consentId) {
-      await deleteBoConsent({
-        boBaseUrl,
-        boToken,
-        consentId: accountData.data.consentId
-      })
-      delete accountData.data.consentId
-      await saveAccountData(accountData)
-    }
-    if (!manualExecution) {
-      throw errors.USER_ACTION_NEEDED_SCA_REQUIRED
-    }
-  }
-
-  // "message_retour_traitement": "Aucun droit d’accès trouvé." OU Obsolète -> create consent
-  return true
-}
-
-/**
- * Creates consents
- * - first in our back-office
- * - then at GRDF
- * @returns {Promise<boolean>} isWaitingForConsentValidation Boolean that indicates that the consent was created and needs a user validation.
- */
-async function createConsent({
-  bearerToken,
-  pce,
-  email,
-  firstname,
-  lastname,
-  postalCode,
-  startDate,
-  endDate,
-  boToken,
-  boBaseUrl
-}) {
-  const startDateString = moment(startDate).format('YYYY-MM-DD')
-  const endDateConsent = moment(endDate).add(1, 'year')
-  const endDateString = endDateConsent.format('YYYY-MM-DD')
-
-  const { ID: consentId } = await createBoConsent({
-    boBaseUrl,
-    boToken,
-    pce,
-    firstname,
-    lastname,
-    postalCode,
-    endDate: endDateConsent
-  }).catch(err => {
-    log('error', `Failed to create BO consent, ${err}`)
-    throw errors.MAINTENANCE
-  })
-
-  // Save BO consentId into account
-  const accountData = await getAccount(ACCOUNT_ID)
-  await saveAccountData(ACCOUNT_ID, {
-    ...accountData.data,
-    consentId: consentId
-  })
-
-  await createGRDFConsent({
-    bearerToken,
-    email,
-    lastname,
-    pce,
-    postalCode,
-    startDate: startDateString,
-    endDate: endDateString
-  }).catch(async err => {
-    await deleteBoConsent({
-      boBaseUrl,
-      boToken,
-      consentId: consentId
-    })
-    throw err
-  })
-
-  return true
-}
-
 /**
  * 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,
diff --git a/src/requests/grdf.js b/src/requests/grdf.js
index d8f95db53ab612a1c5d6ea667d57936f812baf12..86d90837a96c1cd0be7ce7fe75c7dd6a3b39a57c 100644
--- a/src/requests/grdf.js
+++ b/src/requests/grdf.js
@@ -2,6 +2,7 @@
 const { default: Axios } = require('axios')
 const { errors, log } = require('cozy-konnector-libs')
 const qs = require('qs')
+const Sentry = require('@sentry/node')
 
 /**
  *
@@ -109,6 +110,7 @@ async function createGRDFConsent({
   } catch (error) {
     log('error', `Failed to create GRDF consent`)
     log('error', error.response.data)
+    Sentry.captureException('Failed to create GRDF consent')
     throw errors.USER_ACTION_NEEDED_CGU_FORM
   }
 }