PermisAPI
dev PropTech solo ou petite équipe, 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 équipe, 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)

Etape 1. Dependances minimales

Python :

pip install httpx pydantic

Node/TypeScript :

npm install axios zod

Etape 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;
  }
}

Etape 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;
}

Etape 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.

Etape 5. Composant carte

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

Etape 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,
  };
}

Etape 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 });
}

Etape 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 nécessaire 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

  • Enrichissement 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.

Etapes suivantes

  • 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)

Essayez l'API en 30 secondes

Pas d'inscription, pas de carte bleue. Entrez un code postal sur l'accueil et regardez 5 permis en temps reel.

Autres tutoriels