Le favori « Exporter de JD2M » lit votre compte sans rien y changer et télécharge un fichier .json. Comptez environ 2 minutes pour 5 années, avec la liasse PDF, le FEC et l'aide 2042 de chaque année.
Votre navigateur lit le fichier sur cette page, sans compte. Rien n'est envoyé, et Locameublé ne voit jamais votre mot de passe JD2M.
À l'import, chaque année télétransmise est close sur les chiffres déposés : cumul d'amortissement, ARD et déficits. L'année suivante repart de ce que vous avez déclaré.
Chez JD2M, la page de l'offre Essentielle (299 € TTC) renvoie la reprise d'une comptabilité vers l'Intégrale, à 629 € TTC, avec 149 € TTC de supplément. Pages lues le 12 novembre 2026.
Chez Locameublé, l'import est compris dans l'offre Déclaration, à 149 € TTC par an. La télétransmission depuis Locameublé n'est pas encore ouverte.
Exportez vos années JD2M en un fichier, avec la liasse PDF, le FEC et l'aide 2042 de chaque année, puis voyez ce qui sera repris avant de créer un compte. Le fichier est lu dans votre navigateur, rien n'est envoyé.
Ramzi, loueur en meublé depuis 2021. Mis à jour le .
1. Exportez votre dossier JD2M
L'export se fait depuis un ordinateur. Le favori tourne dans le navigateur de l'ordinateur où vous êtes connecté à JD2M. Rouvrez cette page sur votre ordinateur.
Sur app.jedeclaremonmeuble.com.
Le script lit votre compte sans rien y changer et télécharge un fichier .json sur votre ordinateur.
Le favori ne s'installe pas ? Collez le script dans la console
Sur app.jedeclaremonmeuble.com, connecté, ouvrez la console : F12, ou ⌘⌥J sur Mac.
Chrome refuse le premier collage. Tapez autoriser le collage (allow pasting si Chrome
est en anglais), puis Entrée.
Copiez le script ci-dessous, collez-le dans la console, puis Entrée.
Script d'export JD2M
// Export JD2M vers Locameublé : lecture seule (GET), à lancer sur app.jedeclaremonmeuble.com, connecté.
// Console : coller ce fichier. Favori : "javascript:" + encodeURIComponent(ce fichier).
(async () => {
const HOTE = "app.jedeclaremonmeuble.com";
const API = "/apis/public/1.0";
/** @type {(message: string) => never} */
const stop = (message) => {
alert(`Export JD2M\n\n${message}`);
throw new Error(message);
};
if (location.hostname !== HOTE)
stop(
`Ouvrez https://${HOTE}/myspace/, connectez-vous, puis relancez l'export depuis cet onglet.`,
);
const token =
sessionStorage.getItem("token") ||
stop(
"Vous n'êtes pas connecté dans cet onglet. Connectez-vous à votre espace JD2M, puis relancez l'export.",
);
const bandeau = document.createElement("div");
bandeau.style.cssText =
"position:fixed;z-index:2147483647;top:12px;right:12px;padding:12px 16px;background:#111;color:#fff;font:14px system-ui;border-radius:8px;box-shadow:0 4px 16px #0004";
document.body.append(bandeau);
let appels = 0;
let phase = "";
const etat = (texte = phase) => {
phase = texte;
bandeau.textContent = `Export JD2M : ${texte} (${appels} lectures)`;
};
/** @type {{ url: string; http: number; message: string | null }[]} */
const erreurs = [];
// Every call is a GET with the session header: the export never writes to JD2M.
/** @param {string} chemin @param {Record<string, string | number>} params @returns {Promise<any>} */
async function lire(chemin, params = {}) {
const query = new URLSearchParams(Object.entries(params).map(([k, v]) => [k, String(v)]));
const url = `${API}${chemin}?${query}`;
appels++;
etat();
const r = await fetch(url, {
method: "GET",
headers: { Accept: "application/json", "X-TOKEN": token },
});
const corps = await r.json().catch(() => null);
if (r.status === 401 || corps?.status === -401)
stop("Votre session JD2M a expiré. Reconnectez-vous, puis relancez l'export.");
if (!r.ok || corps?.status !== 0) {
erreurs.push({ url, http: r.status, message: corps?.message ?? null });
return null;
}
return corps;
}
/**
* Les listes paginées : JD2M ne demande la page suivante que quand une page revient pleine.
* @param {string} chemin @param {Record<string, string | number>} params @param {number} taillePage
*/
async function lireTout(chemin, params, taillePage) {
/** @type {unknown[]} */
const datas = [];
let premiere = null;
for (let page = 1; ; page++) {
const r = await lire(chemin, { ...params, pageIndex: page });
if (!r) return premiere && { ...premiere, datas };
premiere ??= r;
datas.push(...r.datas);
if (!taillePage || r.datas.length < taillePage || page >= 100) return { ...premiere, datas };
}
}
/** Un fichier de /res (liasse, FEC, aide 2042) en base64 : le lien meurt avec la session, le contenu non. */
/** @param {string | null | undefined} url */
async function fichier(url) {
if (!url) return null;
appels++;
etat();
const r = await fetch(url, { method: "GET", headers: { "X-TOKEN": token } });
if (!r.ok) {
erreurs.push({ url, http: r.status, message: null });
return null;
}
const blob = await r.blob();
const base64 = await new Promise((ok, ko) => {
const fr = new FileReader();
fr.onload = () => ok(String(fr.result).split(",")[1] ?? "");
fr.onerror = () => ko(fr.error);
fr.readAsDataURL(blob);
});
return { type: blob.type, octets: blob.size, base64 };
}
etat("dossier");
const config = await lire("/config/config");
const taillePage = config?.datas?.pageSize ?? 0;
const activites = await lire("/client/activites");
const choisie = Number(sessionStorage.getItem("activite"));
const activite =
activites?.datas?.find((/** @type {{ Oid: number }} */ a) => a.Oid === choisie) ??
activites?.datas?.[0];
if (!activite) stop("Aucune activité trouvée dans ce compte JD2M : rien à exporter.");
const activiteId = activite.Oid;
const fiscyears = await lire("/client/fiscyears", { activiteId });
/** @type {Record<string, unknown>} */
const dossier = { "client-activites.json": activites, "client-fiscyears.json": fiscyears };
dossier["client-paidyears.json"] = await lire("/client/paidyears");
for (const [classe, attribut] of [
["ActiviteRegimeReel", "FraisAcquisition"],
["ActiviteRegimeReel", "FormeJuridique"],
["ActiviteRegimeReel", "FinActiviteCause"],
["Appartement", "Classement"],
["Appartement", "CauseVente"],
["Emprunt", "EcheancesInterval"],
["ExploitantDetail", "SSIAffiliation"],
["ImmobilisationBase", "CauseSortie"],
])
dossier[`enums/${classe}-${attribut}.json`] = await lire("/util/values", { classe, attribut });
/** @type {Record<number, unknown>} */
const annees = {};
/** @type {{ Oid: number; AnneeFiscale: number; Liasse?: unknown }[]} */
const exercices = (fiscyears?.datas ?? []).toSorted(
(/** @type {{ AnneeFiscale: number }} */ a, /** @type {{ AnneeFiscale: number }} */ b) =>
a.AnneeFiscale - b.AnneeFiscale,
);
for (const fy of exercices) {
const annee = fy.AnneeFiscale;
const anneeId = fy.Oid;
const a = { activiteId, anneeId };
/** @type {Record<string, any>} */
const f = {};
etat(`${annee}`);
f["client-fiscyear.json"] = await lire("/client/fiscyear", a);
f["client-activite.json"] = await lire("/client/activite", a);
f["exploitant-list.json"] = await lire("/exploitant/list", a);
f["exploitant-details.json"] = await lire("/exploitant/details", { anneeId });
f["client-comptes.json"] = await lire("/client/comptes", { anneeId });
for (const famille of [6, 7, 16])
f[`client-articles-famille${famille}.json`] = await lire("/client/articles", {
famille,
anneeId,
});
f["logement-list.json"] = await lire("/logement/list", a);
f["logement-immobilisations-all.json"] = await lire("/logement/immobilisations", {
...a,
aptId: 0,
});
f["logement-usage-all.json"] = await lire("/logement/usage", { ...a, aptId: 0 });
for (const l of f["logement-list.json"]?.datas ?? []) {
const p = { ...a, aptId: l.Oid };
f[`logement-${l.Oid}-composants.json`] = await lire("/logement/composants", p);
f[`logement-${l.Oid}-immobilisations.json`] = await lire("/logement/immobilisations", p);
f[`logement-${l.Oid}-usage.json`] = await lire("/logement/usage", p);
}
f["emprunt-list.json"] = await lire("/emprunt/list", a);
for (const e of f["emprunt-list.json"]?.datas ?? [])
f[`emprunt-${e.Oid}-echeances.json`] = await lire("/emprunt/echeances", {
anneeId,
empId: e.Oid,
});
f["depense-list.json"] = await lireTout("/depense/list", { anneeId }, taillePage);
f["recette-list.json"] = await lireTout("/recette/list", { anneeId }, taillePage);
f["document-list.json"] = await lire("/document/list", a);
f["client-liasse-IMMOS.json"] = await lire("/client/liasse", { anneeId, field: "IMMOS" });
// An open year has no liasse yet: its links are absent and the year still exports.
const liasse = f["client-fiscyear.json"]?.datas?.Liasse ?? fy.Liasse ?? null;
etat(`${annee}, liasse et FEC`);
const pieces = {
"liasse-2031-2033.pdf": await fichier(liasse?.UrlLiasse),
"fec.txt": await fichier(liasse?.UrlFEC),
"aide-2042-c-pro.pdf": await fichier(liasse?.Url2042CPRO),
};
annees[annee] = { anneeId, fichiers: f, pieces };
}
const bundle = {
source: "jd2m",
version: 1,
exportedAt: new Date().toISOString(),
activiteId,
autresActivites: (activites?.datas ?? [])
.map((/** @type {{ Oid: number }} */ x) => x.Oid)
.filter((/** @type {number} */ oid) => oid !== activiteId),
lectures: appels,
erreurs,
dossier,
annees,
};
const blob = new Blob([JSON.stringify(bundle)], { type: "application/json" });
const lien = document.createElement("a");
lien.href = URL.createObjectURL(blob);
lien.download = `jd2m-export-${bundle.exportedAt.slice(0, 10)}.json`;
document.body.append(lien);
lien.click();
lien.remove();
setTimeout(() => URL.revokeObjectURL(lien.href), 60_000);
const n = Object.keys(annees).length;
const nb = `${n} année${n > 1 ? "s" : ""}`;
bandeau.textContent = erreurs.length
? `Export JD2M : ${nb}, ${erreurs.length} lectures en échec. Fichier téléchargé, à vérifier.`
: `Export JD2M terminé : ${nb}, fichier téléchargé. Importez-le dans Locameublé.`;
setTimeout(() => bandeau.remove(), 15_000);
return { annees: Object.keys(annees), lectures: appels, erreurs, octets: blob.size };
})();
2. Déposez le fichier et lisez l'aperçu
Ce que l'export prend, et ce qui reste chez JD2M
JD2M ne propose pas d'export de vos données pour les reprendre ailleurs. Votre espace laisse télécharger, année
par année, la liasse en PDF, l'aide à la 2042 et le FEC, ce dernier seulement une fois la liasse télétransmise et
acceptée. Le favori lit le reste tel que votre espace l'affiche : logements, composants, emprunts, et chaque
recette et charge saisie.
Le favori lit, Locameublé reprend les chiffres que vous avez déclarés. Vos documents déposés chez JD2M restent à télécharger.
Un export de 5 années prend environ 2 minutes. Le favori ne fait que des lectures, avec la session déjà ouverte
dans votre navigateur : il ne voit pas votre mot de passe JD2M, et Locameublé non plus.
À télécharger chez JD2M avant de résilier
Même si vous importez tout, gardez une copie à vous. Dans votre espace JD2M, pour chaque année :
la liasse 2031 et 2033 en PDF, celle que vous avez déposée ;
l'aide à la déclaration de revenus, avec les cases de la 2042 C PRO ;
le FEC, s'il y en a un : JD2M ne le produit qu'après la télétransmission ;
les factures et documents que vous avez déposés, que le favori ne télécharge pas.
L'historique de vos amortissements ne sert pas qu'à l'an prochain. Il compte aussi à la revente, comme l'explique
le guide sur la plus-value en LMNP.
Les étapes, dans l'ordre
Sur un ordinateur, glissez le bouton « Exporter de JD2M » dans la barre de favoris.
Ouvrez JD2M, connecté, et cliquez sur le favori. Un fichier .json se télécharge.
Déposez-le plus haut. L'aperçu montre vos années, leur statut, vos logements et vos emprunts.
Si un article JD2M n'a pas d'équivalent, l'aperçu le liste et l'import reste bloqué. Rien n'est deviné à votre
place.
Cliquez sur « Importer dans Locameublé » et créez votre compte : l'import reprend le même fichier.
Les années télétransmises sont closes sur les chiffres déposés, et leurs PDF de liasse et FEC rangés par année.
Ce que coûte le changement
Une reprise n'est pas comprise partout. Pour arriver chez JD2M avec des années déjà déclarées, la page de leur
offre Essentielle, à 299 € TTC, renvoie la reprise vers l'Intégrale, à 629 € TTC plus 120 € par logement
supplémentaire, avec 149 € TTC de supplément. Pour un logement, ça fait 778 € TTC la première année. Prix lus le
12 novembre 2026.
Chez Locameublé, l'import est compris dans l'offre Déclaration, à 149 € TTC par an,
biens illimités. Une limite à connaître avant de partir : la télétransmission depuis Locameublé n'est pas encore
ouverte. Le détail des offres est dans mon avis sur JD2M et le comparatif des logiciels LMNP.
Cette page décrit un outil et des règles générales, sans tenir compte de votre situation fiscale. Elle est publiée par
Locameublé, qui vend un logiciel concurrent de JD2M.
JD2M laisse télécharger, pour chaque année, la liasse en PDF, l'aide à la 2042 et le FEC. Le FEC n'apparaît qu'une fois la liasse télétransmise et acceptée. Le favori de cette page lit en plus vos logements, leurs composants, vos emprunts et vos recettes et charges, tels que votre espace JD2M les affiche.
Le favori peut-il modifier mon compte JD2M ?
Non. Il ne fait que des lectures, avec la session déjà ouverte dans votre navigateur. Il ne demande pas votre mot de passe, et le fichier qu'il produit reste sur votre ordinateur.
Et une année que je n'ai pas encore télétransmise ?
Elle est lue aussi, avec ses recettes et ses charges, et l'aperçu la marque comme ouverte. Elle n'a pas de FEC chez JD2M, puisque JD2M ne le produit qu'après la télétransmission.
Que se passe-t-il si une dépense JD2M n'est pas reconnue ?
L'import est bloqué, et l'aperçu liste chaque article JD2M en cause avec son nombre de lignes. Locameublé ne devine pas un compte à votre place : envoyez-nous la liste à hello@locameuble.fr.
L'export et l'aperçu sont-ils gratuits ?
Oui, sans compte. Pour importer, il faut un compte Locameublé sur l'offre Déclaration, à 149 € TTC par an, avec 14 jours d'essai.
Dois-je résilier JD2M avant d'exporter ?
Non, exportez d'abord : le favori a besoin de votre session JD2M ouverte. Téléchargez aussi vos PDF de liasse et vos FEC depuis votre espace, et gardez-les avec vos justificatifs.
En 10 minutes, ajoutez un bien et son bail, et voyez votre résultat 2026 estimé.