PermisAPI
dev PropTech solo ou petite equipe, pile Next.js / Python.
temps 1-2 heures pour l'integration initiale.budget 0 EUR au demarrage (Free tier PermisAPI, hosting gratuit

Startup PropTech : integrer PermisAPI dans un pipeline Next.js + Postgres

Persona : dev PropTech solo ou petite equipe, pile Next.js / Python. Temps : 1-2 heures pour l'integration initiale. Budget : 0 EUR au demarrage (Free tier PermisAPI, hosting gratuit existant Vercel/Railway/Neon sur le projet PropTech).

Cas d'usage

Tu construis un produit PropTech qui :

  • Affiche une carte de permis pres d'un bien immo
  • Calcule un score "dynamisme du quartier" (volume permis 12 mois)
  • Alerte l'utilisateur quand un nouveau permis > X m2 apparait pres de chez lui

Architecture

PermisAPI <---> Ton backend Python/Node <---> Ta DB (cache) <---> Ton frontend
                                    |
                                    v
                              Ton webhook /alerts (recoit les pushes)

Step 1. Dependances minimales

Python :

pip install httpx pydantic

Node/TypeScript :

npm install axios zod

Step 2. Client TypeScript type-safe

lib/permisapi.ts :

import axios, { AxiosInstance } from "axios";
import { z } from "zod";

const PermitSchema = z.object({
  id: z.number(),
  num_pa: z.string(),
  dep_code: z.string().nullable(),
  comm_code: z.string().nullable(),
  adr_localite_ter: z.string().nullable(),
  full_address: z.string().nullable(),
  lat: z.number().nullable(),
  lng: z.number().nullable(),
  etat_pa: z.number().nullable(),
  date_reelle_autorisation: z.string().nullable(),
  permit_type: z.string().nullable(),
  superficie_terrain: z.number().nullable(),
  denom_dem: z.string().nullable(),
});
type Permit = z.infer<typeof PermitSchema>;

const PageSchema = z.object({
  data: z.array(PermitSchema),
  pagination: z.object({
    page: z.number(),
    limit: z.number(),
    total: z.number(),
    has_next: z.boolean(),
  }),
});

export class PermisAPIClient {
  private http: AxiosInstance;
  constructor(apiKey: string) {
    this.http = axios.create({
      baseURL: "https://api.permisapi.fr",
      headers: { "X-API-Key": apiKey },
      timeout: 10_000,
    });
  }

  async permitsNear(
    lat: number,
    lng: number,
    radiusM = 1000,
    limit = 50
  ): Promise<Permit[]> {
    const resp = await this.http.get("/v1/permits/near", {
      params: { lat, lng, radius_m: radiusM, limit },
    });
    return PageSchema.parse(resp.data).data;
  }

  async statsCommune(code: string) {
    const resp = await this.http.get(`/v1/stats/commune/${code}`);
    return resp.data;
  }
}

Step 3. Cache cote serveur (important)

PermisAPI Free = 500 req/mois. Sans cache, si ton user parcourt 10 biens, tu fais 10 req. 50 users = quota explose.

Strategie : cache Redis / Postgres TTL 1h :

// lib/cachedPermisapi.ts
import { PermisAPIClient } from "./permisapi";

const api = new PermisAPIClient(process.env.PERMISAPI_KEY!);

export async function permitsNearCached(
  lat: number, lng: number, radiusM = 1000
): Promise<Permit[]> {
  // 3 decimales = ~100m. Groupe les requetes dans une tile grossiere.
  const key = `permits:${lat.toFixed(3)}:${lng.toFixed(3)}:${radiusM}`;
  const cached = await redis.get(key);
  if (cached) return JSON.parse(cached);

  const fresh = await api.permitsNear(lat, lng, radiusM);
  await redis.setex(key, 3600, JSON.stringify(fresh));
  return fresh;
}

Step 4. Route Next.js pour ton front

app/api/permits-near/route.ts :

import { NextRequest, NextResponse } from "next/server";
import { permitsNearCached } from "@/lib/cachedPermisapi";

export async function GET(req: NextRequest) {
  const sp = req.nextUrl.searchParams;
  const lat = parseFloat(sp.get("lat")!);
  const lng = parseFloat(sp.get("lng")!);
  if (!lat || !lng) {
    return NextResponse.json({ error: "lat/lng required" }, { status: 400 });
  }
  const permits = await permitsNearCached(lat, lng);
  return NextResponse.json({ permits });
}

Important : n'expose jamais ta cle PermisAPI au browser. Toutes les requetes passent par ton backend.

Step 5. Composant carte

Voir le tuto separe docs/tutorials/05_carte_interactive.md (si ecrit) ou utilise directement MapLibre GL + le composant deja developpe sur notre landing (landing/components/map/).

Step 6. Score dynamisme de quartier

export async function dynamismScore(commCode: string) {
  const stats = await api.statsCommune(commCode);
  const {
    total_permits,
    last_12_months_count,
    trend_yoy_pct,
  } = stats;

  // Formule simple, a ajuster
  const volume = Math.min(last_12_months_count / 100, 1);  // 0-1
  const trend = Math.max(Math.min((trend_yoy_pct || 0) / 50, 1), -1);

  return {
    score: Math.round((volume * 0.6 + (trend + 1) / 2 * 0.4) * 100),
    volume, trend,
    raw: stats,
  };
}

Step 7. Webhook recevoir les alertes

Endpoint de ton backend pour recevoir les POST PermisAPI :

// app/api/permisapi-webhook/route.ts
import crypto from "crypto";

export async function POST(req: NextRequest) {
  const body = await req.text();
  const sig = req.headers.get("x-permisapi-signature") || "";

  // Verification HMAC SHA256
  const expected = crypto
    .createHmac("sha256", process.env.PERMISAPI_WEBHOOK_SECRET!)
    .update(body).digest("hex");
  if (sig !== expected) {
    return NextResponse.json({ error: "invalid signature" }, { status: 401 });
  }

  const event = JSON.parse(body);
  // event = { event: "permit_matched", alert_id, permit: {...} }
  await savePermitToMyDB(event.permit);
  await notifyUser(event.permit);
  return NextResponse.json({ ok: true });
}

Step 8. Deploy

Ton projet PropTech probablement sur Vercel + Neon. Ajoute :

PERMISAPI_KEY=pk_live_...
PERMISAPI_WEBHOOK_SECRET=...
REDIS_URL=... (Upstash free 10k commandes/jour)

Deploy : git push. Rien de plus.

Budget total

  • PermisAPI Free : 0 EUR (Explorer 49 EUR necessaire si > 500 req/mois)
  • Vercel : 0 EUR (Hobby tier)
  • Neon : 0 EUR (Free 512 MB)
  • Upstash Redis : 0 EUR (10k cmd/jour)
  • Total : 0-49 EUR/mois selon volume

Upgrade vers Pro quand ?

A partir de 100 users actifs / jour :

  • 500 req PermisAPI/mois probable

  • Enrichment SIRENE utile pour afficher "demandeur = societe X"
  • Historique > 6 mois utile pour analyses trend

Pro 199 EUR = ~5 EUR/user actif/mois, marge saine pour un SaaS PropTech freemium.

Next steps

  • Integrer DVF (valeurs foncieres) pour estimer prix marche
  • Integrer IRIS INSEE pour socio-demo du quartier
  • Ajouter des alertes webhook pour notification temps reel (plan Pro)

Essaie l'API en 30 secondes

Pas de signup, pas de carte bleue. Entre un code postal sur la home et regarde 5 permis en temps reel.

Autres tutoriels