Comment extraire l'index des immeubles via l'API
Guide pas à pas : commander un index, suivre la tâche, lire les lignes en JSON ou en CSV. Exemples cURL, Python et Node.
Un index des immeubles se commande, se suit puis se lit en trois appels. Chaque inscription de l'index devient une ligne structurée (numéro d'inscription, date de présentation, nature, parties, radiations telles qu'inscrites). Le PDF source est toujours renvoyé avec les lignes, et il fait foi.
Cette page est un guide de l'API. La présentation de l'API Fonciq, ses opérations et ses limites publiées sont sur fonciq.ca.
Prérequis
- Une clé d'API : voir Premier appel. Une clé
fq_test_ne débite rien et renvoie des données d'exemple. - Un compte du Registre foncier de votre organisation, ajouté dans Studio › Développeurs. Sans compte, aucun index ne se commande. Voir Authentification.
1. Commander l'index
POST /v1/registre/requests (portée registre:write) exige un en-tête Idempotency-Key, conservé 24 heures. Une reprise avec la même clé renvoie la même réponse.
curl -X POST https://api.fonciq.ca/v1/registre/requests \
-H "Authorization: Bearer $FONCIQ_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3f1c0b2e-7a4d-4e1a-9c2b-0d5e6f7a8b9c" \
-d '{"lot":"1234567","documents":["index"]}'La réponse est 202 :
{ "job_id": "job_01HZX", "account_id": "rfa_exemple" }2. Suivre la tâche
La consultation est asynchrone. GET /v1/jobs/{id} (portée jobs:read) donne l'état : queued, capacity_wait, running, succeeded ou failed. L'état capacity_wait signifie que le plafond du jour du compte retient encore l'envoi au Registre. La capacité du compte se lit dans la même réponse.
curl https://api.fonciq.ca/v1/jobs/job_01HZX \
-H "Authorization: Bearer $FONCIQ_API_KEY"Interrogez à intervalle raisonnable : la clé est limitée à 60 requêtes par minute (Limites de débit).
3. Lire les lignes
Lorsque la tâche est succeeded, le résultat est sur result.index (un bloc par lot pour un lot groupé). Il donne pdf_url, entries_url et entries. Les mêmes lignes se lisent directement avec GET /v1/documents/{id}/entries, en JSON par défaut ou en CSV avec format=csv.
curl "https://api.fonciq.ca/v1/documents/42/entries?format=csv" \
-H "Authorization: Bearer $FONCIQ_API_KEY"Le PDF source se télécharge avec GET /v1/documents/{id}.
Python
import os, time, uuid, requests
BASE = "https://api.fonciq.ca"
HEADERS = {"Authorization": f"Bearer {os.environ['FONCIQ_API_KEY']}"}
job = requests.post(
f"{BASE}/v1/registre/requests",
headers={**HEADERS, "Idempotency-Key": str(uuid.uuid4())},
json={"lot": "1234567", "documents": ["index"]},
).json()
while True:
state = requests.get(f"{BASE}/v1/jobs/{job['job_id']}", headers=HEADERS).json()
if state["status"] in ("succeeded", "failed"):
break
time.sleep(10)
if state["status"] == "succeeded":
for entry in state["result"]["index"]["entries"]:
print(entry["inscription"], entry["presentation_date"], entry["nature"])Node
const BASE = 'https://api.fonciq.ca';
const headers = { Authorization: `Bearer ${process.env.FONCIQ_API_KEY}` };
const created = await fetch(`${BASE}/v1/registre/requests`, {
method: 'POST',
headers: { ...headers, 'Content-Type': 'application/json', 'Idempotency-Key': crypto.randomUUID() },
body: JSON.stringify({ lot: '1234567', documents: ['index'] }),
}).then((r) => r.json());
let job;
do {
await new Promise((resolve) => setTimeout(resolve, 10_000));
job = await fetch(`${BASE}/v1/jobs/${created.job_id}`, { headers }).then((r) => r.json());
} while (!['succeeded', 'failed'].includes(job.status));
if (job.status === 'succeeded') {
for (const entry of job.result.index.entries) console.log(entry.inscription, entry.nature);
}Ce que contiennent les lignes
| Champ | Contenu |
|---|---|
inscription | Numéro d'inscription, espaces conservés. |
presentation_date | Date de présentation, YYYY-MM-DD. |
nature | Nature de l'acte. Nulle lorsque la colonne n'a pas été lue. |
parties | { "role", "name" }, lorsque la qualité est reconnue. |
radiations | Mentions de radiation telles qu'inscrites : inscription, mention, raw_text. |
confidence | Toujours le littéral unscored : l'analyseur actuel ne produit pas de score. Laissez unscored. |
source_document_id | Identifiant du PDF source. |
Le PDF fait foi. Une liste entries vide est une lecture vide : aucune ligne n'est inventée pour la remplir, et les rangées sans date ou sans numéro d'inscription sont écartées. Le détail de chaque champ est dans Tâches et résultats. Les colonnes du CSV sont les mêmes pour jobs/{id}/results, lots/{lot} et documents/{id}/entries.
Coût
Chaque index livré coûte 0,99 $ excluant frais du registre. L'index consulte toujours le Registre, qui facture 1,50 $ au titulaire du compte : un index consulté coûte donc 2,49 $ au total. Les frais du Registre ne sont pas un débit Fonciq. Une clé fq_test_ ne débite pas. Voir Coûts.
Erreurs fréquentes
| Code | Cause |
|---|---|
401 | Clé absente, révoquée ou sans la portée registre:write ou jobs:read. |
400 | Corps invalide, ou format autre que csv sur une lecture de lignes. |
409 | Aucun compte du Registre : rf_account_required. |
404 | Document qui n'est pas un index produit pour votre organisation. |
429 | Plus de 60 requêtes par minute (rate_limited) : attendez le délai de Retry-After. |
Le corps d'erreur est le même partout : voir Erreurs.
Pour aller plus loin
- Plusieurs lots à la fois : Consultation en lot par CSV ou Lots groupés.
- Être avisé d'une nouvelle inscription : Webhooks des nouvelles inscriptions.