📚 Référence API v1.0

API ArtAI

REST · JSON · authentification par jeton Bearer. Base URL : https://www.artai.fr

Introduction

L'API ArtAI expose l'indice de valeur des artistes (ArtScore) et le pipeline complet de certification des œuvres. Toutes les réponses sont en JSON. Les endpoints de lecture (GET) sont publics ; les écritures requièrent un jeton Bearer. Les réponses d'erreur suivent le format { "error", "message", "status" }.

L'API est entièrement gratuite : aucun crédit, aucun quota, aucun abonnement. Le jeton Bearer sert uniquement à identifier l'auteur des écritures, jamais à les facturer. Pour nous soutenir, rendez visite à notre partenaire montmartre-nft.fr.

🔑 Authentification

Obtenez un jeton d'accès JWT via /api/auth/token, puis passez-le dans l'en-tête Authorization: Bearer <token>. Le jeton expire après 3600 secondes. L'inscription et l'usage de l'API sont gratuits, sans limite de crédits.

POST /api/auth/register

Créer un compte et recevoir un JWT.

{ "email": "you@studio.art", "password": "secret", "displayName": "Studio" }
POST /api/auth/token

Se connecter et obtenir un jeton d'accès JWT.

{ "email": "you@studio.art", "password": "secret" }
// 200 { "token": "eyJ0eXAi...", "tokenType": "Bearer", "expiresIn": 3600 }
GET /api/auth/me 🔒 auth

Utilisateur authentifié courant.

🎟️ Jetons personnels

POST /api/auth/api-tokens 🔒 auth

Créer un jeton d'API personnel (serveur-à-serveur, préfixe sk_).

{ "name": "gallery-integration", "scopes": ["artwork:write"], "expiresInDays": 90 }
GET /api/auth/api-tokens 🔒 auth

Lister ses jetons personnels.

🧑‍🎨 Artistes

GET /api/artists?q=reyes&nature=human&category=ceramics&minScore=50&sort=score&page=1&perPage=24

Rechercher des artistes. Filtres cumulables : q (nom ou pays), nature (human|ai|hybrid), country, category (les artistes qui travaillent dans cette discipline — cf. /api/categories), minScore, sort (score|name|recent), page/perPage. C'est exactement la recherche de la page « Voir une cote ». Les clés data et total ne changent pas, et ?limit reste un alias de perPage.

POST /api/artists 🔒 auth

Créer un artiste. Le site accepte un domaine nu (« marinareyes.art » → https://marinareyes.art) ; socials est un objet { plateforme: identifiant }.

{ "name": "Marina Reyes", "nature": "human", "country": "Espagne", "website": "marinareyes.art", "bio": "Sculptrice contemporaine.", "socials": {"instagram": "@marina"} }
PATCH /api/artist/{ref} 🔒 auth

Mettre à jour le profil d'un artiste (propriétaire ou curateur/admin). PATCH : seuls les champs envoyés changent ; le slug (donc l'URL publique) ne change jamais. Le site accepte un domaine nu.

{ "country": "France", "website": "marinareyes.art", "bio": "…" }
POST /api/artist/{ref}/photo 🔒 auth

Définir la photo de référence de l'artiste (fichier multipart « photo »). Propriétaire ou curateur/admin.

multipart: photo=@marina.jpg
GET /api/artist/{ref}

Détail d'un artiste (id, uuid ou slug).

📊 ArtScore & marché

GET /api/artist/{ref}/score

Indice ArtScore d'un artiste et détail des sous-scores. ?fresh=1 pour recalculer.

// 200 { "index": { "score": 87.4, "grade": "A+", "components": { ... } } }
GET /api/artwork/{ref}/score

ArtScore de l'ŒUVRE elle-même : les sept mêmes familles pondérées que l'indice artiste (physique, marché, reconnaissance, engagement, avis, traçabilité, rareté), notées sur cette seule pièce, quelle que soit sa discipline. Calculé à la volée puis mis en cache ; ?fresh=1 pour recalculer.

// 200 { "index": { "score": 84.6, "grade": "A", "scope": "artwork", "components": { ... } } }
GET /api/artist/{ref}/score/history?granularity=month&limit=24

Progression de la cote dans le temps. Points réels relevés à chaque recalcul (un par jour, le dernier calcul du jour). Les artistes de démonstration renvoient simulated:true sur la série et sur chaque point — une courbe fabriquée n'est jamais présentée comme un historique.

// 200 { "granularity": "month", "simulated": false, "points": [ { "d": "2026-05", "s": 71.2, "g": "A", "simulated": false } ] }
POST /api/artist/{ref}/score/refresh 🔒 auth

Forcer le recalcul du score. Enregistre aussi le point du jour dans l'historique.

GET /api/artist/{ref}/market-index

Synthèse des signaux de marché (ventes, pic, timeline).

POST /api/artist/{ref}/market-record 🔒 auth

Enregistrer une vente / signal de marché.

{ "type": "auction", "price": 4200, "currency": "EUR", "source": "Christies", "soldAt": "2026-03-01" }
POST /api/artist/{ref}/recognition 🔒 auth

Soumettre une reconnaissance (expo, prix, presse…). Toujours créée en « pending » — le champ verified est ignoré.

{ "type": "press", "title": "Portrait", "institution": "Le Monde", "url": "https://www.lemonde.fr/..." }

📐 Cote au point

GET /api/formats

Table de référence des châssis traditionnels français (N° 0-120, F/P/M) et règles de la cote au point.

POST /api/formats/match

Ramener des dimensions libres (cm) au format standard le plus proche. Carrés/double-carrés assimilés ; n°0 = 0,8 point.

{ "width": 92, "height": 73 }
// 200 { "number": 30, "category": "F", "standard": "92×73 cm", "points": 30, "exact": true }
GET /api/artist/{ref}/cote

Cote au point de l'artiste : prix au point dérivé de l'ArtScore + grille d'exemples. Valeur potentielle indicative, jamais un prix fixe.

// 200 { "cote": { "pricePerPointEur": 2, "beginner": true, "exampleGrid": [ ... ] } }
GET /api/artwork/{ref}/estimate

Estimation indicative d'une œuvre = prix au point × points(format) × multiplicateur physique (matériaux, temps, surface/volume) + valeur du cadre (déclarée ou dérivée du type × périmètre). Le format est déduit des dimensions.

// 200 { "estimate": { "adjustedEstimateEur": 79.44, "frame": { "type": "bois doré", "addedValueEur": 264 }, "estimateEur": 343.44 } }

🔒 Confiance & vérification

GET /api/signals/pending 🔒 auth

Lister TOUS les signaux à valider (marché, reconnaissance, avis). Réservé ROLE_CURATOR ou jeton scope signal:verify.

POST /api/signal/{kind}/{id}/verify 🔒 auth

Valider/rejeter un signal (kind = market|recognition|rating). Contrôle de la source (tout site présentant l'œuvre) : liste blanche par catégorie, joignabilité, présence du nom, crédibilité IA. Réservé ROLE_CURATOR ou jeton scope signal:verify.

{ "decision": "verify", "proofUrl": "https://opensea.io/..." }

⭐ Évaluations

POST /api/artist/rating

Soumettre une évaluation pondérée (publique). Le poids dépend du type d'évaluateur.

{ "artist": "ada-lovelace", "raterType": "gallerist", "stars": 5, "criteria": { "originality": 90, "technique": 85 } }

🖼️ Œuvres & pipeline

GET /api/categories

Référentiel des disciplines : pour chaque catégorie, son groupe, le rôle de média par défaut et ceux autorisés, la méthode de cote, et le type de fichier source attendu. C'est ce qui pilote un formulaire de dépôt.

GET /api/artworks?limit=20&category=ceramics

Lister les œuvres, plus récentes d'abord. Filtrable par discipline.

POST /api/artworks 🔒 auth

Déposer une œuvre et lancer le pipeline complet (représentation, stéganographie, C2PA, IPFS, NFT, certificat). Deux champs pilotent tout : category (la discipline — cf. /api/categories) et mediaRole (ce que l'image EST par rapport à l'œuvre : original = elle est l'œuvre ; documentation = elle la montre — sculpture, céramique, mode ; representation = elle la symbolise — musique, texte, vidéo). Omis, mediaRole prend la valeur par défaut de la discipline. Une œuvre non visuelle se dépose avec sourceFile : c'est LUI qui est certifié, et ArtAI en dérive une représentation reproductible. Champs physiques optionnels : materials, materialQuality (0-100), creationHours, depthCm, framed/frameType/frameValue (œuvres planes), durationSeconds, wordCount.

multipart: image=@face.jpg, title=Torse, artistName=Ada, category=sculpture, dimensions=40x50 cm, depthCm=40, materials=bronze, creationHours=80

# œuvre non visuelle — le fichier source est l'œuvre :
multipart: sourceFile=@nocturne.wav, title=Nocturne, artistName=Ada, category=music
GET /api/artwork/{ref}

Détail d'une œuvre avec provenance complète. Renvoie category, mediaRole, imageIs (ce que l'image est) et artScore (l'indice propre de l'œuvre) dans la forme courte ; certifiedHash (l'empreinte réellement scellée — celle du fichier source pour une œuvre non visuelle), scoreBreakdown, source et views dans la forme complète.

POST /api/artwork/{ref}/process 🔒 auth

Relancer / reprendre le pipeline de certification.

{ "steps": { "nft": false } }

🔢 Éditions & unicité

POST /api/artworks/check 🔒 auth

Pré-contrôle d'un dépôt SANS enregistrer : doublon exact (SHA-256), quasi-doublon (hash perceptuel dHash), empreinte visuelle + score de similarité. La question posée dépend du mediaRole : « même image ? » (original), « même objet physique ? » (documentation — le hash perceptuel n'y est qu'un indice, deux angles d'un bronze ne sont pas deux œuvres), « même fichier source ? » (representation). Décision : new_edition / add_piece / edition_full / needs_review.

multipart: artist=ada-lovelace, image=@art.png, category=ceramics, editionSize=10
GET /api/edition/{ref}

Registre public d'une édition : taille, pièces émises, restantes, et la liste numérotée.

📱 Engagement (QR)

POST /api/artwork/{ref}/scan

Enregistrer une interaction QR — l'acte de présence. Public. La présence est dédupliquée par visiteur et par jour : reflasher renvoie newPresence:false, pas une seconde présence. Pose un cookie visiteur au 1er scan et renvoie un voteToken à courte durée qui autorise UN avis de ce visiteur sur l'œuvre. C'est ce qui rend la fréquentation authentifiée — sans la déduplication, n'importe quel téléphone gonflait l'engagement à chaque requête.

{ "action": "scan", "country": "FR", "city": "Paris", "durationSeconds": 42 }
POST /api/artwork/{ref}/visitor-rating

Avis d'un VISITEUR sur l'œuvre qu'il vient de flasher — une seule fois par visiteur. Public, mais exige le voteToken renvoyé par /scan (corps ou en-tête X-Vote-Token) : pas de scan, pas d'avis. Un vote rejoué renvoie 409 already_rated. Le poids est fixé au niveau « visiteur » et ne peut pas surpondérer l'ArtScore. Limite honnête : un navigateur ne donne pas d'identifiant matériel stable, l'ancre est un cookie — navigation privée = nouveau visiteur ; la garantie est qu'un visiteur normal vote une fois et que tricher demande un effort délibéré.

{ "voteToken": "<du POST /scan>", "stars": 5, "comment": "magnifique" }
POST /api/artwork/{ref}/review 🔒 auth

Attacher un avis QUALIFIÉ (professionnel) à une œuvre. Exige un compte authentifié — c'est le chemin galeriste/critique/acheteur, pas celui du visiteur anonyme (cf. /visitor-rating). Non dédupliqué par appareil : un pro peut légitimement noter plusieurs œuvres.

{ "raterType": "collector", "stars": 4, "criteria": { "emotionalImpact": 80 } }
GET /api/artist/{ref}/exhibition-impact

Fréquentation authentifiée et tunnel de conversion.

🎫 Certificats

POST /api/certificate/generate 🔒 auth

Générer le certificat d'authenticité PDF.

{ "artwork": "<uuid>" }
GET /api/certificate/{serial}

Récupérer un certificat par son numéro de série.

✅ Vérification

GET /api/qrcode/{token}/verify

Vérifier l'authenticité d'une œuvre depuis son jeton QR. Réextrait la signature stéganographique et revalide le C2PA en direct.

// 200 { "authentic": true, "trustScore": 100, "checks": { ... } }
GET /api/artwork/{ref}/c2pa

Provenance C2PA : manifeste enregistré (assertions signées au dépôt) + revérification live via c2patool --detailed.

// 200 { "status": "signed", "recordedManifest": {...}, "liveVerification": { "valid": true, "manifest": {...} } }

🤝 Partenaires

ArtAI est une infrastructure B2B : des plateformes tierces (galeries, sites culturels, marketplaces NFT — p.ex. montmartre-nft.fr, antenne-culture.fr) intègrent ArtAI. Le partenaire possède ses propres utilisateurs ; l'accès à l'API est gratuit et illimité — aucun quota, aucune mesure d'usage facturée.

Le partenaire gère
ses utilisateurs finaux · leur login · les appels API (jeton sk_)
ArtAI gère
l'émission du jeton (1×) · la preuve de domaine · la curation (jamais déléguée)
Cycle de vie
  1. Candidature — le partenaire s'inscrit (POST /apply) et reçoit un challenge DNS TXT.
  2. Preuve de domaine — il publie le TXT, puis /verify-domain confirme qu'il possède le domaine.
  3. Validation — vous (ROLE_ADMIN) approuvez via /approve ou php bin/console app:partner:approve : provisioning du compte de service et d'un jeton 🔒 scopé (affiché une seule fois).
  4. Self-service — le partenaire consulte son profil (/me) et peut choisir son propre réseau blockchain (/me/blockchain).

Gratuité : aucun crédit n'est décompté, aucun quota n'est appliqué. Un partenaire suspendu (abus) voit son jeton immédiatement rejeté.

📄 Document de référence complet →

POST /api/partners/apply

Candidature d'un partenaire revendeur (galerie, plateforme culturelle…). Crée une demande « pending » et renvoie un challenge DNS TXT à publier pour prouver la propriété du domaine. Public.

{ "name": "Antenne Culture", "domain": "antenne-culture.fr", "contactEmail": "tech@antenne-culture.fr", "expectedVolume": 300 }
// 200 { "partner": { "uuid": "…", "status": "pending" }, "domainVerification": { "record": { "type": "TXT", "value": "artai-verify=…" } } }
POST /api/partners/{ref}/verify-domain

Revérifie le challenge DNS TXT. Une fois prouvé, un admin peut valider. Public.

GET /api/partners/{ref}

Statut public d'une candidature (id, uuid ou domaine).

POST /api/partners/{ref}/approve 🔒 auth

Valide un partenaire : provisionne un compte de service et un jeton d'API scopé (usage gratuit et illimité). Renvoie le jeton une seule fois. ROLE_ADMIN.

{ "force": false }
// 200 { "apiToken": "sk_…", "scopes": ["artwork:write", …] }
POST /api/partners/{ref}/suspend 🔒 auth

Suspend un partenaire ; son jeton d'API est immédiatement rejeté. ROLE_ADMIN.

GET /api/partners/me 🔒 auth

Partenaire courant : profil et réseau blockchain. Authentifié avec le jeton sk_ du partenaire.

// 200 { "partner": { "uuid": "…", "status": "active" }, "blockchain": { "ownChain": false } }

🩺 Meta

GET /api/health

État du service et capacités (IPFS, C2PA, NFT).

GET /api/openapi

Spécification OpenAPI 3.1 (JSON).

Exemple complet (cURL)

# 1. Obtenir un jeton
TOKEN=$(curl -s -X POST https://www.artai.fr/api/auth/token \
  -H "Content-Type: application/json" \
  -d '{"email":"you@studio.art","password":"secret"}' | jq -r .token)

# 2. Déposer une œuvre (lance tout le pipeline)
curl -X POST https://www.artai.fr/api/artworks \
  -H "Authorization: Bearer $TOKEN" \
  -F "image=@artwork.png" -F "title=Aurora" -F "artistName=Ada Lovelace" \
  -F "creationType=ai" -F "aiModel=Midjourney v6" -F "price=1200"

# 3. Vérifier publiquement
curl https://www.artai.fr/api/qrcode/<token>/verify

🔌 Serveur MCP (agents IA)

ArtAI expose un serveur Model Context Protocol (MCP) qui transforme l'API ci-dessus en outils utilisables directement depuis un assistant IA (Claude Desktop, Claude Code, ou tout client compatible MCP). Un galeriste, un collectionneur ou un agent tiers peut ainsi demander « Quel est l'ArtScore et la cote de l'artiste X ? » ou « Cette œuvre est-elle authentifiée ? » — ArtAI répond comme source de vérité vérifiée.

Portée : 14 outils de lecture (score, cote, estimation, formats, vérification QR/C2PA…) accessibles anonymement, plus 1 outil d'écriture protégé artai_certify_artwork (pipeline de certification) qui exige un jeton 🔒 artwork:write et une confirmation explicite avant toute mutation.

14 × READ artai_get_artist_score · artai_get_artist_cote · artai_estimate_artwork · artai_verify_qrcode · …

Chaque outil correspond 1:1 à un endpoint REST ; aucune logique n'est dupliquée. La liste complète est décrite dans le mcp/README.md du dépôt.

2 × WRITE artai_save_artist · artai_certify_artwork 🔒 auth + confirm

artai_save_artist crée ou met à jour le profil d'un artiste (pays, site de référence, bio, réseaux, nature) ; artai_certify_artwork lance le pipeline de certification. Sans confirm:true, chaque outil renvoie un aperçu (dry-run) sans rien modifier — garde-fou humain contre les actions irréversibles (ancrage IPFS, mint NFT).

Brancher le serveur (Claude Desktop / Claude Code)

# build
cd mcp && npm install && npm run build

# Claude Code
claude mcp add artai -- node /chemin/vers/mcp/dist/index.js

# Claude Desktop — claude_desktop_config.json
{
  "mcpServers": {
    "artai": {
      "command": "node",
      "args": ["/chemin/vers/mcp/dist/index.js"],
      "env": { "ARTAI_BASE_URL": "https://www.artai.fr" }
    }
  }
}