{"openapi":"3.0.0","info":{"title":"IT-Tools API","description":"Documentation de l\u0027API REST IT-Tools \u2014 outils PDF, formulaires CERFA et conversion de documents.\n\n---\n\n## Automatisation sans code : Zapier, Make, n8n\n\nL\u0027API s\u0027utilise directement depuis les outils d\u0027automatisation, sans \u00e9crire de code :\n**Zapier**, **Make**, **n8n** et tout outil capable d\u0027envoyer une requ\u00eate HTTP. Remplir un\nCERFA \u00e0 chaque nouvelle r\u00e9ponse d\u0027un formulaire, fusionner ou compresser des PDF re\u00e7us par\ne-mail, g\u00e9n\u00e9rer un QR code \u00e0 chaque commande : chaque outil de l\u0027API devient une \u00e9tape de\nvotre sc\u00e9nario.\n\n- **Zapier** : action \u00ab Webhooks by Zapier \u00bb (Custom Request).\n- **Make** : module \u00ab HTTP \u00bb (Make a request).\n- **n8n** : n\u0153ud \u00ab HTTP Request \u00bb.\n\nDans chacun, appelez la route voulue (voir ci-dessous) avec les en-t\u00eates `X-Api-Key` et\n`X-Api-Secret` de votre [cl\u00e9 API](https:\/\/it-tools.plateformweb.com\/account). Les outils\ncompatibles OpenAPI peuvent aussi importer la sp\u00e9cification de l\u0027API externe, limit\u00e9e aux\nroutes `\/api\/v1\/*` : `\/api\/doc\/external.json`.\n\n---\n\n## Authentification par cl\u00e9 API\n\nLes cl\u00e9s API donnent acc\u00e8s aux **endpoints de l\u0027API externe** (`\/api\/v1\/*` : PDF,\nOffice, images, QR codes, CERFA, montants en lettres, booklets, kit d\u0027images et\noutils d\u00e9veloppeur : JSON, YAML, CSV, JWT, hash, UUID, dates, couleurs\u2026).\nElles sont g\u00e9n\u00e9r\u00e9es et g\u00e9r\u00e9es exclusivement depuis votre [espace compte](https:\/\/it-tools.plateformweb.com\/account).\n\n\u003E **Important** \u2014 La gestion du compte (email, mot de passe, suppression, cl\u00e9s API) est r\u00e9serv\u00e9e\n\u003E au frontend. Aucun endpoint de modification de compte n\u0027est accessible via cl\u00e9 API.\n\n---\n\n### Mode Browser (frontend \/ JavaScript)\n\nEnvoyez uniquement la **cl\u00e9 publique** (`pk_\u2026`) dans le header `X-Api-Key`.\nLe serveur v\u00e9rifie que le header `Origin` (ou `Referer`) correspond \u00e0 un domaine autoris\u00e9 sur votre cl\u00e9.\n\n```\nX-Api-Key: pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nOrigin: https:\/\/app.monsite.com\n```\n\n\u003E La cl\u00e9 publique peut \u00eatre expos\u00e9e dans du code JavaScript. La s\u00e9curit\u00e9 repose sur la restriction de domaine.\n\u003E Si aucun domaine n\u0027est configur\u00e9 sur la cl\u00e9, ce mode est refus\u00e9.\n\n---\n\n### Mode Serveur (backend \/ server-to-server)\n\nEnvoyez la **cl\u00e9 publique** ET la **cl\u00e9 priv\u00e9e** (`sk_\u2026`).\nAucune v\u00e9rification de domaine n\u0027est effectu\u00e9e \u2014 la cl\u00e9 priv\u00e9e est le secret.\n\n```\nX-Api-Key: pk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\nX-Api-Secret: sk_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\n```\n\n\u003E La cl\u00e9 priv\u00e9e ne doit **jamais** \u00eatre expos\u00e9e c\u00f4t\u00e9 client.\n\u003E Elle est affich\u00e9e une seule fois \u00e0 la cr\u00e9ation \u2014 conservez-la en lieu s\u00fbr.\n\n---\n\n## Gestion des cl\u00e9s\n\nCr\u00e9ez, listez et r\u00e9voquez vos cl\u00e9s API depuis votre [espace compte](https:\/\/it-tools.plateformweb.com\/account).\n\n**Scope disponible :**\n- `tools` \u2014 acc\u00e8s \u00e0 tous les endpoints de l\u0027API externe (`\/api\/v1\/*`)\n\n---\n\n## Fonctionnement des traitements\n\nLes routes qui produisent un fichier (PDF fusionn\u00e9, CERFA rempli, etc.) r\u00e9pondent en JSON avec\nun champ `download_url` : le fichier se r\u00e9cup\u00e8re ensuite par un second appel `GET` sur cette URL,\n**avec les m\u00eames en-t\u00eates d\u0027authentification**. Le lien est \u00e0 usage unique. Seul le\ntraitement est d\u00e9compt\u00e9 du quota mensuel : le t\u00e9l\u00e9chargement ne l\u0027est pas et reste possible\nquota atteint.\n\n### G\u00e9n\u00e9rer un CERFA\n\n1. `GET \/api\/v1\/cerfa` \u2014 catalogue des CERFA remplissables (`cerfaId`).\n2. `GET \/api\/v1\/cerfa\/{cerfaId}\/fields` \u2014 champs du formulaire : `name` (cl\u00e9 \u00e0 utiliser), `altName` (libell\u00e9), `type`, `options`.\n3. `POST \/api\/v1\/cerfa\/{cerfaId}\/generate` avec `{\u0022data\u0022: {\u0022f1\u0022: \u0022valeur\u0022, ...}}`.\n   Les cl\u00e9s sont celles de `\/fields` et `\/template` (noms anonymis\u00e9s `fN`) ; toute autre cl\u00e9 est ignor\u00e9e.\n4. `GET` sur le `download_url` re\u00e7u pour r\u00e9cup\u00e9rer le PDF.\n\n`GET \/api\/v1\/cerfa\/{cerfaId}\/template` renvoie directement le corps `data` \u00e0 compl\u00e9ter.\n\n---\n\n## Quota et limites\n\nChaque appel de traitement authentifi\u00e9 par cl\u00e9 API (`X-Api-Key` seule ou combin\u00e9e \u00e0\n`X-Api-Secret`) est d\u00e9compt\u00e9 du quota mensuel du forfait associ\u00e9 \u00e0 votre\ncompte. Les t\u00e9l\u00e9chargements par `download_url` ne sont pas d\u00e9compt\u00e9s :\n\n| Forfait | Quota mensuel |\n|---|---|\n| D\u00e9couverte | 100 appels\/mois |\n| Premium (9,99 \u20ac\/mois) | 5 000 appels\/mois |\n| Pro (29,99 \u20ac\/mois) | 50 000 appels\/mois |\n\nAu-del\u00e0 du quota, l\u0027API r\u00e9pond :\n\n```\nHTTP\/1.1 429 Too Many Requests\n{\u0022message\u0022: \u0022Quota d\u0027appels API mensuel atteint pour votre forfait.\u0022}\n```\n\nLe quota se r\u00e9initialise automatiquement le **1er de chaque mois**.\n\nInd\u00e9pendamment du quota, une limite de d\u00e9bit par adresse IP prot\u00e8ge les traitements les\nplus lourds (par exemple 20 g\u00e9n\u00e9rations de CERFA par tranche de 5 minutes). Au-del\u00e0,\nl\u0027API r\u00e9pond aussi `429 Too Many Requests` : patientez quelques minutes ou espacez les\nappels dans votre sc\u00e9nario.\n\n\u003E La consommation actuelle n\u0027est aujourd\u0027hui consultable que depuis votre\n\u003E [espace compte](https:\/\/it-tools.plateformweb.com\/account) \u2014 il n\u0027existe\n\u003E pas d\u0027endpoint d\u00e9di\u00e9 permettant \u00e0 une cl\u00e9 API externe d\u0027interroger son\n\u003E propre quota restant.\n","version":"v1","x-logo":{"url":"\/assets\/icons\/android-chrome-192x192.png","altText":"IT-Tools"},"x-application-version":"5.2.0"},"paths":{"\/api\/v1\/tools\/number-to-words\/currencies":{"get":{"tags":["Outils"],"summary":"Lister les devises support\u00e9es","operationId":"get_api_v1_tools_number_to_words_currencies","responses":{"200":{"description":"Liste des devises"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/number-to-words\/convert":{"post":{"tags":["Outils"],"summary":"Convertir un montant en lettres","operationId":"post_api_v1_tools_number_to_words_convert","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["amount"],"properties":{"amount":{"type":"string","example":"1234.56"},"currency":{"type":"string","example":"EUR"}},"type":"object"}}}},"responses":{"200":{"description":"Montant converti","content":{"application\/json":{"schema":{"properties":{"result":{"type":"string"}},"type":"object"}}}},"400":{"description":"Montant invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/image\/formats":{"get":{"tags":["Outils"],"summary":"Lister les formats d\u0027image support\u00e9s","operationId":"get_api_v1_tools_image_formats","responses":{"200":{"description":"Liste des formats"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/image\/convert":{"post":{"tags":["Outils"],"summary":"Convertir une image","description":"Convertit une image vers un autre format (WebP, AVIF, JPG, PNG, GIF, BMP).","operationId":"post_api_v1_tools_image_convert","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["file"],"properties":{"file":{"type":"string","format":"binary"},"format":{"type":"string","default":"webp","enum":["webp","avif","jpg","png","gif","bmp"]},"quality":{"type":"integer","default":85},"maxWidth":{"description":"Largeur max en px (optionnel)","type":"integer"}},"type":"object"}}}},"responses":{"200":{"description":"Image convertie (binaire)"},"400":{"description":"Fichier ou format invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/qrcode\/logos":{"get":{"tags":["QR Code"],"summary":"Lister les logos disponibles","operationId":"get_api_v1_tools_qrcode_logos","responses":{"200":{"description":"Liste des logos pr\u00e9d\u00e9finis"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/qrcode\/generate":{"post":{"tags":["QR Code"],"summary":"G\u00e9n\u00e9rer un QR code","description":"G\u00e9n\u00e8re un QR code et retourne un data URI base64 (SVG ou PNG).","operationId":"post_api_v1_tools_qrcode_generate","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["content"],"properties":{"content":{"type":"string","example":"https:\/\/example.com"},"type":{"type":"string","default":"url","enum":["url","text","email","phone","sms","wifi","vcard","geo"]},"format":{"type":"string","default":"svg","enum":["svg","png"]},"size":{"type":"integer","default":300},"honeypot":{"description":"Champ cach\u00e9 anti-bot (doit rester vide) \u2014 utilis\u00e9 uniquement pour un QR de type \u0022url\u0022 cr\u00e9\u00e9 anonymement.","type":"string"},"formElapsedMs":{"description":"D\u00e9lai (ms) entre le rendu du formulaire et sa soumission \u2014 utilis\u00e9 uniquement pour un QR de type \u0022url\u0022 cr\u00e9\u00e9 anonymement.","type":"integer"},"altchaPayload":{"description":"Payload base64 de la preuve de travail Altcha (voir GET \/api\/tools\/qrcode\/altcha-challenge), requis uniquement pour un QR de type \u0022url\u0022 cr\u00e9\u00e9 anonymement.","type":"string"}},"type":"object"}}}},"responses":{"200":{"description":"QR code g\u00e9n\u00e9r\u00e9","content":{"application\/json":{"schema":{"properties":{"dataUri":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/qrcode\/icon-to-svg":{"post":{"tags":["QR Code"],"summary":"Convertir une image en SVG logo","description":"Retourne le SVG en base64 pr\u00eat \u00e0 \u00eatre utilis\u00e9 comme logo custom.","operationId":"post_api_v1_tools_qrcode_icon_to_svg","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["file"],"properties":{"file":{"type":"string","format":"binary"},"bgColor":{"type":"string","example":"#ffffff"},"shape":{"type":"string","default":"circle","enum":["circle","square"]},"transparent":{"description":"Si \u0022true\u0022, aucun badge de fond n\u0027est dessin\u00e9 derri\u00e8re l\u0027image (bgColor ignor\u00e9).","type":"string","default":"false","enum":["true","false"]}},"type":"object"}}}},"responses":{"200":{"description":"SVG g\u00e9n\u00e9r\u00e9","content":{"application\/json":{"schema":{"properties":{"dataUri":{"type":"string"}},"type":"object"}}}},"400":{"description":"Fichier invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/booklet\/create":{"post":{"tags":["Booklet"],"summary":"Cr\u00e9er un mini-site booklet","operationId":"post_api_v1_tools_booklet_create","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["title"],"properties":{"title":{"type":"string"},"subtitle":{"type":"string"},"coverColor":{"type":"string","example":"#6C63FF"},"headerColor":{"type":"string","example":"#6C63FF"},"footerColor":{"type":"string","example":"#6C63FF"},"fontFamily":{"type":"string","enum":["inter","poppins","roboto","montserrat","playfair-display","lora"],"example":"inter"},"coverImage":{"description":"Image de couverture optionnelle","type":"string","format":"binary"},"logoImage":{"description":"Logo optionnel","type":"string","format":"binary"},"sections":{"description":"Tableau JSON encod\u00e9 en cha\u00eene (multipart)","type":"string"},"expiresAt":{"type":"string","format":"date"},"qrForeground":{"description":"Couleur de premier plan du QR (d\u00e9faut #000000).","type":"string","example":"#000000"},"qrBackground":{"description":"Couleur de fond du QR (d\u00e9faut #ffffff).","type":"string","example":"#ffffff"},"qrMotifStyle":{"description":"Style des modules du QR (d\u00e9faut square).","type":"string","enum":["square","dot","round"]},"qrEyeStyle":{"description":"Style des yeux du QR (d\u00e9faut square).","type":"string","enum":["square","circle"]},"qrLogoKey":{"description":"Cl\u00e9 d\u0027un logo pr\u00e9d\u00e9fini (voir GET \/api\/tools\/qrcode\/logos) \u2014 exclusif avec qrLogo.","type":"string"},"qrLogo":{"description":"Logo custom pour le QR, exclusif avec qrLogoKey (pr\u00e9vaut si les deux sont transmis).","type":"string","format":"binary"},"honeypot":{"description":"Champ cach\u00e9 anti-bot (doit rester vide) \u2014 utilis\u00e9 uniquement en cr\u00e9ation anonyme.","type":"string"},"formElapsedMs":{"description":"D\u00e9lai (ms) entre le rendu du formulaire et sa soumission \u2014 utilis\u00e9 uniquement en cr\u00e9ation anonyme.","type":"integer"},"altchaPayload":{"description":"Payload base64 de la preuve de travail Altcha (voir GET \/api\/tools\/qrcode\/altcha-challenge), requis uniquement en cr\u00e9ation anonyme.","type":"string"}},"type":"object"}}}},"responses":{"201":{"description":"Booklet cr\u00e9\u00e9","content":{"application\/json":{"schema":{"properties":{"slug":{"type":"string"},"url":{"type":"string"},"requiresAccount":{"description":"true si le booklet a \u00e9t\u00e9 cr\u00e9\u00e9 anonymement \u2014 non finalis\u00e9 tant qu\u0027il n\u0027est pas rattach\u00e9 \u00e0 un compte (voir POST \/app\/account\/booklet\/claim).","type":"boolean"},"qrDataUri":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides ou contr\u00f4le anti-abus \u00e9chou\u00e9"},"413":{"description":"Contenu trop volumineux"},"415":{"description":"Type de fichier refus\u00e9"},"429":{"description":"Quota anti-abus d\u00e9pass\u00e9 (cr\u00e9ation anonyme)"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/booklet\/{slug}":{"get":{"tags":["Booklet"],"summary":"Afficher un booklet","operationId":"get_api_v1_tools_booklet_show","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Booklet","content":{"application\/json":{"schema":{"properties":{"data":{"description":"Vid\u00e9 si requiresAccount=true (aper\u00e7u de couverture uniquement).","type":"array","items":{}},"requiresAccount":{"description":"true si le booklet a \u00e9t\u00e9 cr\u00e9\u00e9 anonymement et n\u0027est pas encore rattach\u00e9 \u00e0 un compte \u2014 voir POST \/app\/account\/booklet\/claim.","type":"boolean"},"qrCodeUrl":{"description":"URL de t\u00e9l\u00e9chargement\/r\u00e9g\u00e9n\u00e9ration du QR avec les options de style actuelles \u2014 voir GET \/api\/tools\/booklet\/{slug}\/qrcode.","type":"string"},"qrForeground":{"type":"string"},"qrBackground":{"type":"string"},"qrMotifStyle":{"type":"string","enum":["square","dot","round"]},"qrEyeStyle":{"type":"string","enum":["square","circle"]},"qrLogoKey":{"type":"string","nullable":true}},"type":"object"}}}},"404":{"description":"Introuvable ou expir\u00e9"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/booklet\/{slug}\/cover":{"get":{"tags":["Booklet"],"summary":"Image de couverture du booklet","operationId":"get_api_v1_tools_booklet_cover","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Image de couverture"},"404":{"description":"Booklet, image ou fichier introuvable"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/booklet\/{slug}\/logo":{"get":{"tags":["Booklet"],"summary":"Logo du booklet","operationId":"get_api_v1_tools_booklet_logo","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Logo"},"404":{"description":"Booklet, image ou fichier introuvable"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/booklet\/{slug}\/qrcode":{"get":{"tags":["Booklet"],"summary":"T\u00e9l\u00e9charger\/r\u00e9g\u00e9n\u00e9rer le QR code du booklet","description":"Retourne le contenu brut (pas de data URI base64) pour permettre un\nvrai t\u00e9l\u00e9chargement de fichier c\u00f4t\u00e9 frontend.","operationId":"get_api_v1_tools_booklet_qrcode","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"format","in":"query","required":false,"schema":{"type":"string","default":"svg","enum":["svg","png"]}}],"responses":{"200":{"description":"QR code (image\/svg+xml ou image\/png)"},"404":{"description":"Booklet introuvable ou expir\u00e9"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/image-kit\/create":{"post":{"tags":["Image Kit"],"summary":"Cr\u00e9er un job de g\u00e9n\u00e9ration de kit d\u0027images","description":"Traitement asynchrone (Symfony Messenger) \u2014 retourne imm\u00e9diatement un jobId \u00e0 interroger via \/status.","operationId":"post_api_v1_tools_image_kit_create","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["image","presets"],"properties":{"image":{"type":"string","format":"binary"},"presets":{"description":"Liste s\u00e9par\u00e9e par des virgules : desktop,mobile,avatar","type":"string"},"formats":{"description":"Liste s\u00e9par\u00e9e par des virgules : avif,webp (d\u00e9faut : les deux)","type":"string"},"watermarkText":{"description":"Texte de filigrane optionnel (100 caract\u00e8res max)","type":"string"},"watermarkColor":{"description":"Couleur hex du filigrane (ex. #000000), d\u00e9faut noir","type":"string"},"watermarkAngle":{"description":"Angle d\u0027inclinaison du filigrane en degr\u00e9s (-90 \u00e0 90). Absent\/null = diagonale automatique","type":"integer","nullable":true},"watermarkRepeat":{"description":"Nombre de r\u00e9p\u00e9titions du filigrane en motif (1 \u00e0 12), d\u00e9faut 1","type":"integer"},"watermarkOpacity":{"description":"Opacit\u00e9 du texte du filigrane (0.1 \u00e0 1.0), d\u00e9faut 0.75","type":"number","format":"float"}},"type":"object"}}}},"responses":{"202":{"description":"Job cr\u00e9\u00e9","content":{"application\/json":{"schema":{"properties":{"jobId":{"type":"integer"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"},"415":{"description":"Type de fichier refus\u00e9"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/image-kit\/{jobId}\/status":{"get":{"tags":["Image Kit"],"summary":"Consulter le statut d\u0027un job","description":"N\u00e9cessite le param\u00e8tre de requ\u00eate `ownerToken` retourn\u00e9 par POST \/create \u2014 sans lui (ou avec une valeur invalide), le job est trait\u00e9 comme introuvable (404) pour \u00e9viter de confirmer son existence.","operationId":"get_api_v1_tools_image_kit_status","parameters":[{"name":"jobId","in":"path","required":true,"schema":{"type":"string","pattern":"\\d+"}},{"name":"ownerToken","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Statut du job","content":{"application\/json":{"schema":{"properties":{"status":{"type":"string","enum":["pending","processing","done","failed"]},"download_url":{"type":"string","nullable":true},"message":{"type":"string","nullable":true}},"type":"object"}}}},"404":{"description":"Job introuvable ou ownerToken invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/image-kit\/download\/{filename}\/{token}":{"get":{"tags":["Image Kit"],"summary":"T\u00e9l\u00e9charger le kit d\u0027images g\u00e9n\u00e9r\u00e9","description":"Lien \u00e0 usage unique g\u00e9n\u00e9r\u00e9 apr\u00e8s passage du job \u00e0 `done`.","operationId":"get_api_v1_tools_image_kit_download","parameters":[{"name":"filename","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Archive ZIP du kit d\u0027images"},"404":{"description":"Token invalide ou expir\u00e9"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/cerfa":{"get":{"tags":["CERFA"],"summary":"Lister le catalogue des CERFA remplissables","description":"Retourne le catalogue en base des CERFA remplissables (pr\u00e9sence d\u0027une ligne = CERFA remplissable).","operationId":"get_api_v1_cerfa_list","responses":{"200":{"description":"Liste","content":{"application\/json":{"schema":{"properties":{"available":{"type":"array","items":{"properties":{"cerfaId":{"type":"string","example":"13750-07"},"intitule":{"type":"string","example":"Demande de duplicata du certificat d\u0027immatriculation"},"categories":{"type":"array","items":{"type":"string"}},"updatedAt":{"type":"string","format":"date-time"}},"type":"object"}}},"type":"object"}}}}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/cerfa\/{cerfaId}\/fields":{"get":{"tags":["CERFA"],"summary":"Lister les champs AcroForm d\u0027un CERFA","description":"Retourne tous les champs du formulaire via pdftk dump_data_fields.","operationId":"get_api_v1_cerfa_fields","parameters":[{"name":"cerfaId","in":"path","required":true,"schema":{"type":"string","pattern":"[A-Za-z0-9*\\-]{1,32}"}}],"responses":{"200":{"description":"Champs","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean"},"fields":{"type":"array","items":{"type":"object"}}},"type":"object"}}}},"404":{"description":"PDF CERFA non disponible"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/cerfa\/{cerfaId}\/template":{"get":{"tags":["CERFA"],"summary":"Gabarit JSON pr\u00eat \u00e0 remplir pour un CERFA","description":"Retourne directement le corps JSON attendu par POST \/api\/cerfa\/{cerfaId}\/generate, avec toutes les valeurs vides \u2014 \u00e9vite de reconstruire cette structure \u00e0 partir de \/fields.","operationId":"get_api_v1_cerfa_template","parameters":[{"name":"cerfaId","in":"path","required":true,"schema":{"type":"string","pattern":"[A-Za-z0-9*\\-]{1,32}"}}],"responses":{"200":{"description":"Gabarit","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean"},"cerfaId":{"type":"string"},"data":{"description":"Champ \u2192 valeur (vide)","type":"object"}},"type":"object"},"example":{"success":true,"cerfaId":"16341-01","data":{"f1":"","f2":"","f3":"","f4":"","f5":"","f6":"","f7":"","f8":"","f9":"","f10":"","f11":"","f12":"","f13":"","f14":"","f15":"","f16":"","f17":"","f18":"","f19":"","f20":"","f21":"","f22":"","f23":"","f24":""}}}}},"404":{"description":"PDF CERFA non disponible"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/cerfa\/{cerfaId}\/generate":{"post":{"tags":["CERFA"],"summary":"Remplir et g\u00e9n\u00e9rer un CERFA","description":"Remplit le PDF CERFA avec les donn\u00e9es JSON fournies et retourne un lien de t\u00e9l\u00e9chargement. Les cl\u00e9s de \u0022data\u0022 sont celles renvoy\u00e9es par \/template et \/fields (noms anonymis\u00e9s) : toute autre cl\u00e9 est ignor\u00e9e. Disponible aussi sous \/api\/v1\/cerfa\/{cerfaId}\/generate pour l\u0027API externe (X-Api-Key + X-Api-Secret).","operationId":"post_api_v1_cerfa_generate","parameters":[{"name":"cerfaId","in":"path","required":true,"schema":{"type":"string","pattern":"[A-Za-z0-9*\\-]{1,32}"}}],"requestBody":{"required":true,"content":{"application\/json":{"schema":{"properties":{"data":{"description":"Champ \u2192 valeur","type":"object"}},"type":"object"},"example":{"data":{"f1":"France","f2":"CPAM de Paris","f3":"9 99 99 99 999 999 99","f4":"15\/03\/1985","f5":"75001","f6":"12 rue de la Paix, 75001 Paris","f7":"Assur\u00e9","f8":"Paris","f9":"15\/03\/1985","f10":"Dupont Jean","f11":"Dupont Jean","f12":"0612345678","f13":"Chute dans l\u0027escalier","f14":"Paris","f15":"01\/09\/2026","f16":"01\/09\/2026","f17":"Salari\u00e9","f18":"Ouvrier","f19":"jean.dupont@example.com","f20":"Oui","f21":"78","f22":"14","f23":"30","f24":"Non"}}}}},"responses":{"200":{"description":"PDF g\u00e9n\u00e9r\u00e9","content":{"application\/json":{"schema":{"properties":{"success":{"type":"boolean"},"download_url":{"type":"string"}},"type":"object"}}}},"404":{"description":"PDF CERFA non disponible"},"422":{"description":"Erreur de g\u00e9n\u00e9ration"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/json\/format":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Formater et valider du JSON","description":"Valide le JSON et le renvoie indent\u00e9 (2 ou 4 espaces). Passer le JSON sous forme de cha\u00eene pr\u00e9serve exactement les objets vides `{}`.","operationId":"post_api_v1_tools_dev_json_format","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["json"],"properties":{"json":{"description":"Cha\u00eene JSON, ou objet \/ tableau JSON","example":"{\u0022name\u0022:\u0022Jean\u0022,\u0022age\u0022:30}"},"indent":{"type":"integer","default":2,"enum":[2,4]}},"type":"object"}}}},"responses":{"200":{"description":"JSON format\u00e9 (`result`)"},"400":{"description":"JSON invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/json\/minify":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Minifier du JSON","operationId":"post_api_v1_tools_dev_json_minify","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["json"],"properties":{"json":{"description":"Cha\u00eene JSON, ou objet \/ tableau JSON","example":"{ \u0022a\u0022: 1, \u0022b\u0022: [1, 2] }"}},"type":"object"}}}},"responses":{"200":{"description":"JSON minifi\u00e9 (`result`) et tailles en octets"},"400":{"description":"JSON invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/json-yaml\/convert":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Convertir JSON vers YAML ou YAML vers JSON","description":"YAML limit\u00e9 \u00e0 256 Ko ; le document d\u00e9velopp\u00e9 est born\u00e9 (500 000 noeuds, 64 niveaux), ce qui rejette les expansions d\u0027alias abusives. Les tags et objets PHP ne sont pas interpr\u00e9t\u00e9s.","operationId":"post_api_v1_tools_dev_json_yaml","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["input"],"properties":{"input":{"description":"Contenu \u00e0 convertir (JSON ou YAML selon `direction`)","example":"{\u0022a\u0022:[1,2]}"},"direction":{"type":"string","default":"json-to-yaml","enum":["json-to-yaml","yaml-to-json"]},"indent":{"description":"Indentation du JSON produit (yaml-to-json)","type":"integer","default":2,"enum":[2,4]}},"type":"object"}}}},"responses":{"200":{"description":"Contenu converti (`result`)"},"400":{"description":"Entr\u00e9e invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/json-to-csv\/convert":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Convertir un tableau JSON en CSV","description":"Les colonnes sont celles du premier objet (500 colonnes et 1 000 000 de cellules au maximum). `neutralizeFormulas` pr\u00e9fixe d\u0027une apostrophe les textes et en-t\u00eates commen\u00e7ant par `=`, `+`, `-` ou `@` (injection de formules Excel).","operationId":"post_api_v1_tools_dev_json_csv","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["json"],"properties":{"json":{"description":"Cha\u00eene JSON, ou tableau d\u0027objets","example":"[{\u0022nom\u0022:\u0022Alice\u0022,\u0022age\u0022:30},{\u0022nom\u0022:\u0022Bob\u0022,\u0022age\u0022:25}]"},"separator":{"type":"string","default":",","enum":[",",";","|","tab"]},"headers":{"type":"boolean","default":true},"neutralizeFormulas":{"type":"boolean","default":false}},"type":"object"}}}},"responses":{"200":{"description":"CSV (`result`), nombre de lignes et colonnes"},"400":{"description":"JSON invalide ou n\u0027\u00e9tant pas un tableau d\u0027objets"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/jwt\/decode":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"D\u00e9coder un JWT","description":"D\u00e9code l\u0027en-t\u00eate et le contenu sans v\u00e9rifier la signature (`signatureVerified` vaut toujours false). Aucun secret n\u0027est accept\u00e9.","operationId":"post_api_v1_tools_dev_jwt_decode","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["token"],"properties":{"token":{"type":"string","example":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxMjMifQ.signature"}},"type":"object"}}}},"responses":{"200":{"description":"En-t\u00eate, contenu, dates des revendications et \u00e9tat d\u0027expiration (`result`)"},"400":{"description":"Token mal form\u00e9"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/ipv4-subnet\/calculate":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Calculer un sous-r\u00e9seau IPv4","operationId":"post_api_v1_tools_dev_ipv4_subnet","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["cidr"],"properties":{"cidr":{"type":"string","example":"192.168.1.10\/24"}},"type":"object"}}}},"responses":{"200":{"description":"R\u00e9seau, broadcast, masque, plage d\u0027h\u00f4tes, classe (`result`)"},"400":{"description":"Notation CIDR invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/chmod\/calculate":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Convertir des permissions chmod","description":"Fournissez exactement un des champs `octal`, `symbolic` ou `permissions` ; les deux autres repr\u00e9sentations sont calcul\u00e9es.","operationId":"post_api_v1_tools_dev_chmod","requestBody":{"required":true,"content":{"application\/json":{"schema":{"properties":{"octal":{"type":"string","example":"755"},"symbolic":{"type":"string","example":"rwxr-xr-x"},"permissions":{"type":"object","example":{"owner":{"r":true,"w":true,"x":true},"group":{"r":true,"w":false,"x":true},"other":{"r":true,"w":false,"x":true}}}},"type":"object"}}}},"responses":{"200":{"description":"Notations octale, symbolique, table et commande (`result`)"},"400":{"description":"Entr\u00e9e invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/url\/parse":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"D\u00e9composer une URL","description":"Analyse syntaxique uniquement : l\u0027URL n\u0027est jamais appel\u00e9e.","operationId":"post_api_v1_tools_dev_url_parse","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["url"],"properties":{"url":{"type":"string","example":"https:\/\/example.com:8080\/path?foo=bar\u0026lang=fr#section"}},"type":"object"}}}},"responses":{"200":{"description":"Protocole, h\u00f4te, port, chemin, param\u00e8tres, fragment, origine (`result`)"},"400":{"description":"URL invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/slugify":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Transformer un texte en slug","operationId":"post_api_v1_tools_dev_slugify","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["text"],"properties":{"text":{"type":"string","example":"\u00c9t\u00e9 \u00e0 Paris !"},"separator":{"type":"string","default":"-","enum":["-","_","."]},"lowercase":{"type":"boolean","default":true}},"type":"object"}}}},"responses":{"200":{"description":"Slug (`result`)"},"400":{"description":"Entr\u00e9e invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/case\/convert":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Convertir la casse d\u0027un texte","description":"Sans `case`, renvoie toutes les conversions dans `results` (texte limit\u00e9 \u00e0 100 Ko). Avec `case`, `result` contient la conversion demand\u00e9e.","operationId":"post_api_v1_tools_dev_case_convert","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["text"],"properties":{"text":{"type":"string","example":"hello world"},"case":{"type":"string","enum":["lower","upper","title","camel","pascal","snake","kebab","screaming","dot","constant","sentence","alternating"]}},"type":"object"}}}},"responses":{"200":{"description":"Textes convertis"},"400":{"description":"Entr\u00e9e invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/text-statistics":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Statistiques d\u0027un texte","operationId":"post_api_v1_tools_dev_text_statistics","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["text"],"properties":{"text":{"type":"string","example":"Bonjour le monde."}},"type":"object"}}}},"responses":{"200":{"description":"Caract\u00e8res, mots, phrases, paragraphes, temps de lecture, fr\u00e9quences (`result`)"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/html-entities\/convert":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Encoder ou d\u00e9coder des entit\u00e9s HTML","operationId":"post_api_v1_tools_dev_html_entities","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["text"],"properties":{"text":{"type":"string","example":"\u003Ca href=\u0022x\u0022\u003E\u00e9\u003C\/a\u003E"},"mode":{"type":"string","default":"encode","enum":["encode","decode"]},"encodeAll":{"description":"Encoder aussi tous les caract\u00e8res non ASCII (mode encode)","type":"boolean","default":false}},"type":"object"}}}},"responses":{"200":{"description":"Texte converti (`result`)"},"400":{"description":"Entr\u00e9e invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/base64\/convert":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Encoder ou d\u00e9coder du Base64","description":"Texte UTF-8 uniquement. Au d\u00e9codage, les variantes base64url (`-` et `_`) et les espaces sont accept\u00e9s.","operationId":"post_api_v1_tools_dev_base64","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["text"],"properties":{"text":{"type":"string","example":"Bonjour"},"mode":{"type":"string","default":"encode","enum":["encode","decode"]},"urlSafe":{"description":"Produire du base64url sans padding (mode encode)","type":"boolean","default":false}},"type":"object"}}}},"responses":{"200":{"description":"Texte converti (`result`)"},"400":{"description":"Base64 invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/hash":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Calculer des empreintes SHA","operationId":"post_api_v1_tools_dev_hash","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["text"],"properties":{"text":{"type":"string","example":"abc"},"algorithms":{"description":"Par d\u00e9faut : sha1, sha256, sha384, sha512","type":"array","items":{"type":"string","enum":["sha1","sha256","sha384","sha512"]}}},"type":"object"}}}},"responses":{"200":{"description":"Empreintes hexad\u00e9cimales par algorithme (`result`)"},"400":{"description":"Algorithme non support\u00e9"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/uuid":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"G\u00e9n\u00e9rer des UUID","operationId":"post_api_v1_tools_dev_uuid","requestBody":{"content":{"application\/json":{"schema":{"properties":{"count":{"type":"integer","default":1,"maximum":100,"minimum":1},"version":{"type":"string","default":"v4","enum":["v4","v7"]},"uppercase":{"type":"boolean","default":false},"withoutDashes":{"type":"boolean","default":false}},"type":"object"}}}},"responses":{"200":{"description":"Premier UUID (`result`) et liste compl\u00e8te (`results`)"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/password":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"G\u00e9n\u00e9rer des mots de passe","description":"G\u00e9n\u00e9r\u00e9s par un g\u00e9n\u00e9rateur cryptographique, avec au moins un caract\u00e8re de chaque jeu activ\u00e9. Rien n\u0027est stock\u00e9.","operationId":"post_api_v1_tools_dev_password","requestBody":{"content":{"application\/json":{"schema":{"properties":{"count":{"type":"integer","default":1,"maximum":50,"minimum":1},"length":{"type":"integer","default":16,"maximum":128,"minimum":4},"lowercase":{"type":"boolean","default":true},"uppercase":{"type":"boolean","default":true},"numbers":{"type":"boolean","default":true},"symbols":{"type":"boolean","default":false},"excludeSimilar":{"description":"Exclure les caract\u00e8res ambigus il1Lo0O","type":"boolean","default":false}},"type":"object"}}}},"responses":{"200":{"description":"Premier mot de passe (`result`) et liste avec niveau de robustesse (`results`)"},"400":{"description":"Aucun jeu de caract\u00e8res activ\u00e9"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/token":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"G\u00e9n\u00e9rer des jetons al\u00e9atoires","operationId":"post_api_v1_tools_dev_token","requestBody":{"content":{"application\/json":{"schema":{"properties":{"count":{"type":"integer","default":1,"maximum":100,"minimum":1},"length":{"type":"integer","default":32,"maximum":1024,"minimum":1},"format":{"type":"string","default":"hex","enum":["hex","base64","alphanumeric","numeric","upper","lower","custom"]},"custom":{"description":"Jeu de caract\u00e8res (format custom)","type":"string","maxLength":256}},"type":"object"}}}},"responses":{"200":{"description":"Premier jeton (`result`) et liste compl\u00e8te (`results`)"},"400":{"description":"Entr\u00e9e invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/timestamp\/convert":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Convertir un timestamp ou une date","description":"Sans `value`, convertit l\u0027instant pr\u00e9sent. Un entier sup\u00e9rieur ou \u00e9gal \u00e0 10^11 est lu en millisecondes, sinon en secondes. Une cha\u00eene est lue comme une date ISO 8601.","operationId":"post_api_v1_tools_dev_timestamp","requestBody":{"content":{"application\/json":{"schema":{"properties":{"value":{"description":"Timestamp Unix ou date ISO 8601","example":1700000000},"timezone":{"type":"string","default":"UTC","example":"Europe\/Paris"}},"type":"object"}}}},"responses":{"200":{"description":"Repr\u00e9sentations de l\u0027instant (`result`)"},"400":{"description":"Date ou fuseau invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/date\/add":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Ajouter ou retrancher une dur\u00e9e \u00e0 une date","description":"Calendrier exact. Comme en JavaScript, 31 janvier + 1 mois donne le 2 ou 3 mars. Valeur n\u00e9gative pour retrancher.","operationId":"post_api_v1_tools_dev_date_add","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["date","value"],"properties":{"date":{"type":"string","example":"2024-01-31"},"value":{"type":"integer","maximum":100000,"minimum":-100000,"example":7},"unit":{"type":"string","default":"days","enum":["days","weeks","months","years"]}},"type":"object"}}}},"responses":{"200":{"description":"Date r\u00e9sultante (`result`)"},"400":{"description":"Entr\u00e9e invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/date\/diff":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Calculer l\u0027\u00e9cart entre deux dates","description":"\u00c9cart sign\u00e9 en jours (n\u00e9gatif si `to` pr\u00e9c\u00e8de `from`) et d\u00e9composition calendaire exacte en ann\u00e9es, mois et jours.","operationId":"post_api_v1_tools_dev_date_diff","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["from","to"],"properties":{"from":{"type":"string","example":"2024-01-31"},"to":{"type":"string","example":"2025-03-01"}},"type":"object"}}}},"responses":{"200":{"description":"\u00c9cart (`result`)"},"400":{"description":"Date invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/fake-data\/fields":{"get":{"tags":["Outils d\u00e9veloppeur"],"summary":"Lister les champs et locales des fausses donn\u00e9es","operationId":"get_api_v1_tools_dev_fake_data_fields","responses":{"200":{"description":"Champs disponibles (cl\u00e9, libell\u00e9, cat\u00e9gorie) et locales (`result`)"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/fake-data":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"G\u00e9n\u00e9rer des fausses donn\u00e9es","description":"Les valeurs sont fictives (cartes, IBAN, e-mails r\u00e9serv\u00e9s aux exemples). `seed` rend le r\u00e9sultat reproductible. 20 000 valeurs au maximum par appel.","operationId":"post_api_v1_tools_dev_fake_data","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["fields"],"properties":{"fields":{"type":"array","items":{"type":"string"},"example":["prenom","nom","email","ville"]},"count":{"type":"integer","default":10,"maximum":1000,"minimum":1},"locale":{"type":"string","default":"fr","enum":["fr","en","de","es","it","nl","pl","pt_br","ru","ja","zh_cn","ar"]},"seed":{"type":"integer"}},"type":"object"}}}},"responses":{"200":{"description":"Tableau d\u0027objets (`result`)"},"400":{"description":"Champ ou locale inconnu"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/lorem":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"G\u00e9n\u00e9rer du texte Lorem Ipsum","operationId":"post_api_v1_tools_dev_lorem","requestBody":{"content":{"application\/json":{"schema":{"properties":{"mode":{"type":"string","default":"paragraphs","enum":["paragraphs","sentences","words"]},"count":{"description":"Maximum 100 paragraphes, 500 phrases ou 2000 mots","type":"integer","default":5,"maximum":2000,"minimum":1},"minWords":{"description":"Mode sentences","type":"integer","default":5,"maximum":100,"minimum":1},"maxWords":{"description":"Mode sentences","type":"integer","default":15,"maximum":100,"minimum":1},"startWithLorem":{"type":"boolean","default":true},"format":{"type":"string","default":"plain","enum":["plain","html"]},"seed":{"type":"integer"}},"type":"object"}}}},"responses":{"200":{"description":"Texte (`result`)"},"400":{"description":"Entr\u00e9e invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/dev\/color\/convert":{"post":{"tags":["Outils d\u00e9veloppeur"],"summary":"Convertir une couleur (HEX, RGB, HSL, HSV, CMYK)","operationId":"post_api_v1_tools_dev_color","requestBody":{"required":true,"content":{"application\/json":{"schema":{"required":["color"],"properties":{"color":{"description":"#RGB, #RRGGBB, \u0022rgb(r, g, b)\u0022 ou objet {r, g, b}","example":"#006EDC"}},"type":"object"}}}},"responses":{"200":{"description":"Couleur dans tous les formats (`result`)"},"400":{"description":"Couleur invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/office-to-pdf":{"post":{"tags":["Office"],"summary":"Convertir un document Office en PDF","description":"Convertit un fichier Word, Excel, PowerPoint, ODT, ODS, ODP, RTF, TXT ou HTML en PDF via LibreOffice.","operationId":"post_api_v1_tools_office_to_pdf","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["file"],"properties":{"file":{"description":"Document Office \u00e0 convertir","type":"string","format":"binary"}},"type":"object"}}}},"responses":{"200":{"description":"PDF g\u00e9n\u00e9r\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Fichier invalide ou format non support\u00e9"},"422":{"description":"Conversion \u00e9chou\u00e9e"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/tools\/pdf-to-word":{"post":{"tags":["Office"],"summary":"Convertir un PDF en DOCX","description":"Convertit un PDF en document Word (DOCX) via LibreOffice. La fid\u00e9lit\u00e9 de mise en page peut varier.","operationId":"post_api_v1_tools_pdf_to_word","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["file"],"properties":{"file":{"description":"PDF \u00e0 convertir en DOCX","type":"string","format":"binary"}},"type":"object"}}}},"responses":{"200":{"description":"DOCX g\u00e9n\u00e9r\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Fichier invalide"},"422":{"description":"Conversion \u00e9chou\u00e9e"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/download\/{filename}\/{token}":{"get":{"tags":["PDF"],"summary":"T\u00e9l\u00e9charger un fichier trait\u00e9","description":"Lien \u00e0 usage unique g\u00e9n\u00e9r\u00e9 apr\u00e8s chaque traitement.","operationId":"get_api_v1_pdf_download","parameters":[{"name":"filename","in":"path","required":true,"schema":{"type":"string"}},{"name":"token","in":"path","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Fichier PDF en t\u00e9l\u00e9chargement"},"404":{"description":"Token invalide ou expir\u00e9"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/merge":{"post":{"tags":["PDF"],"summary":"Fusionner des PDF","description":"Fusionne au moins 2 fichiers PDF en un seul.","operationId":"post_api_v1_pdf_merge","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdfs"],"properties":{"pdfs":{"description":"Au moins 2 fichiers PDF","type":"array","items":{"type":"string","format":"binary"}}},"type":"object"}}}},"responses":{"200":{"description":"PDF fusionn\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/split":{"post":{"tags":["PDF"],"summary":"D\u00e9couper un PDF","description":"D\u00e9coupe un PDF en pages individuelles ou par plages.","operationId":"post_api_v1_pdf_split","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"mode":{"type":"string","default":"all","enum":["all","ranges"]},"ranges":{"description":"Ex. \u00221-3, 5\u0022 \u2014 requis si mode=ranges","type":"string"}},"type":"object"}}}},"responses":{"200":{"description":"ZIP des pages","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/delete-pages":{"post":{"tags":["PDF"],"summary":"Supprimer des pages","operationId":"post_api_v1_pdf_delete_pages","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf","pages"],"properties":{"pdf":{"type":"string","format":"binary"},"pages":{"description":"Ex. \u00222, 4-6\u0022","type":"string"}},"type":"object"}}}},"responses":{"200":{"description":"PDF sans les pages supprim\u00e9es","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/repair":{"post":{"tags":["PDF"],"summary":"R\u00e9parer un PDF corrompu","operationId":"post_api_v1_pdf_repair","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"}},"type":"object"}}}},"responses":{"200":{"description":"PDF r\u00e9par\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/compress":{"post":{"tags":["PDF"],"summary":"Compresser un PDF","operationId":"post_api_v1_pdf_compress","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"level":{"type":"string","default":"medium","enum":["low","medium","high"]}},"type":"object"}}}},"responses":{"200":{"description":"PDF compress\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/to-images":{"post":{"tags":["PDF"],"summary":"Convertir un PDF en images","description":"Convertit chaque page en PNG ou JPG via Ghostscript. Retourne une archive ZIP.","operationId":"post_api_v1_pdf_to_images","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"dpi":{"type":"integer","default":150,"enum":[72,96,150,300]},"format":{"type":"string","default":"png","enum":["png","jpg"]}},"type":"object"}}}},"responses":{"200":{"description":"ZIP des images","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/rotate":{"post":{"tags":["PDF"],"summary":"Pivoter les pages d\u0027un PDF","operationId":"post_api_v1_pdf_rotate","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"rotation":{"type":"string","default":"90","enum":["90","180","270"]},"pageTarget":{"type":"string","default":"all","enum":["all","odd","even","specific"]},"pages":{"description":"Ex. \u00221, 3-5\u0022 \u2014 requis si pageTarget=specific","type":"string"}},"type":"object"}}}},"responses":{"200":{"description":"PDF pivot\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/protect":{"post":{"tags":["PDF"],"summary":"Prot\u00e9ger un PDF par mot de passe","operationId":"post_api_v1_pdf_protect","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf","userPassword"],"properties":{"pdf":{"type":"string","format":"binary"},"userPassword":{"description":"Mot de passe d\u0027ouverture","type":"string"},"ownerPassword":{"description":"Mot de passe propri\u00e9taire (optionnel)","type":"string"},"allowPrint":{"type":"boolean","default":true},"allowCopy":{"type":"boolean","default":false}},"type":"object"}}}},"responses":{"200":{"description":"PDF prot\u00e9g\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/unlock":{"post":{"tags":["PDF"],"summary":"Supprimer la protection d\u0027un PDF","operationId":"post_api_v1_pdf_unlock","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"password":{"description":"Mot de passe du PDF (laisser vide si aucun)","type":"string"}},"type":"object"}}}},"responses":{"200":{"description":"PDF d\u00e9verrouill\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Mot de passe incorrect"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/edit":{"post":{"tags":["PDF"],"summary":"Modifier un PDF","description":"Aplatit les formulaires (flatten) ou extrait des pages (extract).","operationId":"post_api_v1_pdf_edit","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"action":{"type":"string","default":"flatten","enum":["flatten","extract"]},"pages":{"description":"Ex. \u00221-3\u0022 \u2014 requis si action=extract","type":"string"}},"type":"object"}}}},"responses":{"200":{"description":"PDF modifi\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/add-watermark":{"post":{"tags":["PDF"],"summary":"Ajouter un filigrane","description":"Ajoute un filigrane texte ou image sur toutes les pages du PDF.","operationId":"post_api_v1_pdf_add_watermark","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"type":{"type":"string","default":"text","enum":["text","image"]},"text":{"description":"Texte du filigrane (si type=text)","type":"string"},"fontSize":{"type":"integer","default":48},"opacity":{"description":"0-100","type":"integer","default":30},"watermarkImage":{"description":"Image (si type=image)","type":"string","format":"binary"}},"type":"object"}}}},"responses":{"200":{"description":"PDF avec filigrane","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/add-page-numbers":{"post":{"tags":["PDF"],"summary":"Ajouter des num\u00e9ros de pages","operationId":"post_api_v1_pdf_add_page_numbers","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"position":{"type":"string","default":"bottom-center","enum":["bottom-center","bottom-left","bottom-right","top-center","top-left","top-right"]},"startFrom":{"type":"integer","default":1},"fontSize":{"type":"integer","default":12}},"type":"object"}}}},"responses":{"200":{"description":"PDF num\u00e9rot\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/sign":{"post":{"tags":["PDF"],"summary":"Apposer une signature sur un PDF","operationId":"post_api_v1_pdf_sign","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"},"signatureType":{"type":"string","default":"draw","enum":["draw","upload","text"]},"signatureImage":{"description":"Image\/PDF de signature (si type=draw\/upload)","type":"string","format":"binary"},"signatureText":{"description":"Texte de signature (si type=text)","type":"string"},"page":{"description":"Num\u00e9ro de page cible","type":"integer","default":1}},"type":"object"}}}},"responses":{"200":{"description":"PDF sign\u00e9","content":{"application\/json":{"schema":{"properties":{"download_url":{"type":"string"}},"type":"object"}}}},"400":{"description":"Donn\u00e9es invalides"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}},"\/api\/v1\/pdf\/info":{"post":{"tags":["PDF"],"summary":"Lire les m\u00e9tadonn\u00e9es d\u0027un PDF","description":"Retourne les m\u00e9tadonn\u00e9es compl\u00e8tes d\u0027un PDF (titre, auteur, pages, taille, version, chiffrement\u2026) via Poppler pdfinfo.","operationId":"post_api_v1_pdf_info","requestBody":{"required":true,"content":{"multipart\/form-data":{"schema":{"required":["pdf"],"properties":{"pdf":{"type":"string","format":"binary"}},"type":"object"}}}},"responses":{"200":{"description":"M\u00e9tadonn\u00e9es PDF","content":{"application\/json":{"schema":{"properties":{"info":{"type":"object"}},"type":"object"}}}},"400":{"description":"Fichier invalide"}},"security":[{"apiKeyPublic":[],"apiKeyPrivate":[]},{"apiKeyPublic":[]}]}}},"components":{"schemas":{"ApiKeyItem":{"description":"Repr\u00e9sentation d\u0027une cl\u00e9 API (sans la cl\u00e9 priv\u00e9e)","properties":{"publicKey":{"description":"Cl\u00e9 publique \u00e0 inclure dans le header X-Api-Key","type":"string","example":"pk_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"},"name":{"type":"string","example":"Mon site prod"},"scopes":{"type":"array","items":{"type":"string","enum":["tools"]},"example":["tools"]},"allowedDomains":{"description":"Domaines autoris\u00e9s en mode browser. Vide = mode serveur uniquement.","type":"array","items":{"type":"string"},"example":["app.monsite.com"]},"allowedIps":{"description":"Whitelist IP pour le mode serveur. Vide = toutes les IPs autoris\u00e9es.","type":"array","items":{"type":"string"},"example":["1.2.3.4","5.6.7.8"]},"seenIps":{"description":"Historique des IPs ayant utilis\u00e9 cette cl\u00e9 (mode serveur, max 20 entr\u00e9es). Utile pour d\u00e9tecter si une cl\u00e9 est partag\u00e9e entre plusieurs serveurs.","type":"array","items":{"properties":{"ip":{"type":"string","example":"1.2.3.4"},"firstSeen":{"type":"string","example":"2026-03-09 14:30"},"lastSeen":{"type":"string","example":"2026-03-09 15:00"},"count":{"type":"integer","example":42}},"type":"object"}},"isActive":{"type":"boolean","example":true},"createdAt":{"type":"string","example":"2026-03-09 14:30"},"lastUsedAt":{"type":"string","example":"2026-03-09 15:00","nullable":true}},"type":"object"},"ApiKeyCreated":{"allOf":[{"$ref":"#\/components\/schemas\/ApiKeyItem"},{"description":"Retourn\u00e9 uniquement \u00e0 la cr\u00e9ation \u2014 contient la cl\u00e9 priv\u00e9e en clair","required":["privateKey"],"properties":{"privateKey":{"description":"Affiche une seule fois a la creation. Conservez-la immediatement.","type":"string","example":"sk_a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4"}},"type":"object"}]}},"securitySchemes":{"apiKeyPublic":{"type":"apiKey","description":"Cl\u00e9 publique (`pk_\u2026`) g\u00e9n\u00e9r\u00e9e depuis votre espace compte.\nEn mode browser : combin\u00e9e avec un header `Origin` correspondant \u00e0 un domaine autoris\u00e9.\nEn mode serveur : combin\u00e9e avec `X-Api-Secret`.\n","name":"X-Api-Key","in":"header"},"apiKeyPrivate":{"type":"apiKey","description":"Cl\u00e9 priv\u00e9e (`sk_\u2026`) \u2014 mode serveur uniquement.\n\u00c0 combiner obligatoirement avec `X-Api-Key`.\nNe jamais exposer c\u00f4t\u00e9 client.\n","name":"X-Api-Secret","in":"header"}}},"tags":[{"name":"Outils","description":"Outils de conversion et g\u00e9n\u00e9ration (PDF, QR code, images\u2026)"},{"name":"Outils d\u00e9veloppeur","description":"Utilitaires de calcul et de conversion (JSON, YAML, CSV, JWT, hash, UUID, dates, couleurs\u2026), disponibles uniquement via l\u0027API externe \/api\/v1\/tools\/dev\/*"},{"name":"QR Code"},{"name":"Booklet"},{"name":"Image Kit"},{"name":"CERFA"},{"name":"Office"},{"name":"PDF"}]}