API

Créez un lien pour chaque abonné au moment où il ouvre un numéro, publiez vos numéros depuis votre chaîne de production, lisez vos statistiques.

Authentification et permissions

Adresse : https://liseuse-pdf.com/api/gestion/v1. Chaque appel porte Authorization: Bearer lsp_…. Créez et révoquez vos clés dans Intégrations ; une clé voit les numéros de votre compte et rien d’autre. Elle reste sur votre serveur : jamais dans une page web ou une application mobile. Donnez un nom à votre outil dans User-Agent : les agents par défaut de certaines bibliothèques sont bloqués par le pare-feu.

PermissionDonne accès à
lectureGET /publications, GET /numeros, GET /statistiques, GET /compte
liensPOST /liens, POST /liens/revoquer
publicationPOST /televersements, POST /numeros, PATCH /numeros

Spécification OpenAPI 3.1 : /docs/openapi.json, à importer dans Postman, Insomnia ou votre générateur de client.

POST /liens

Corps : id (obligatoire), jours (1 à 365, par défaut votre réglage), page, reference (votre identifiant d’abonné, 80 caractères parmi lettres, chiffres et _ . : @ + -). La référence n’apparaît pas en clair dans le lien : seule une empreinte y figure. Utilisez un identifiant interne plutôt qu’une adresse e-mail. Réponse 201.

terminal
curl -X POST https://liseuse-pdf.com/api/gestion/v1/liens \
  -H "Authorization: Bearer lsp_…" -H "Content-Type: application/json" \
  -H "User-Agent: mon-site/1.0" -H "Idempotency-Key: abonne-42-escales-12" \
  -d '{"id": "liseuse-pdf.com:inklura-escales-n12", "jours": 1, "reference": "CLI-042"}'
201 Created
{
  "url": "https://liseuse-pdf.com/lire/…",
  "expire_le": "2026-10-02T21:49:48.000Z",
  "iframe": "<iframe src=\"…\" width=\"100%\" height=\"720\" …></iframe>"
}

POST /liens/revoquer

Corps : {"reference": "CLI-042"}. Tous les liens créés avec cette référence, pour tous vos numéros, cessent de fonctionner (le lecteur voit « Ce lien de lecture a été désactivé » et la page publique). Les liens créés ensuite avec la même référence fonctionnent : appelez-le à la fin d’un abonnement, pas à son renouvellement. Disponible aussi sur la fiche de chaque numéro.

GET /publications

Paramètres : publication (code du titre), limite (1 à 200, 50 par défaut). GET /numeros?id=… renvoie un seul numéro sous la même forme.

200 OK
{
  "publications": [{
    "id": "liseuse-pdf.com:inklura-escales-n12",
    "titre": "Escales n°12 · octobre 2026",
    "publication": { "code": "escales", "nom": "Escales" },
    "date": "2026-10-01", "pages": 12, "acces": "abonnes",
    "page_publique": "https://liseuse-pdf.com/apercu/inklura-escales-n12",
    "lecture_libre": null,
    "couverture": "https://liseuse-pdf.com/fichiers/escales-n12/couverture.jpg"
  }]
}

Publier un numéro

En deux temps : demandez où envoyer le fichier, envoyez-le, puis créez le numéro. Les fichiers sont identifiés par leur empreinte SHA-256 : un fichier déjà stocké n’est pas renvoyé (deja_present: true). Les SDK font tout en un appel (publier).

1. POST /televersements

Corps : type (pdf ou couverture, un JPEG), sha256, taille (octets), domaine (liseuse-pdf.com par défaut). Réponse : url (valable 1 heure), methode (PUT), en_tetes. Envoyez le fichier tel quel avec ces en-têtes.

2. POST /numeros

ChampRôle
sha256, tailleLe PDF envoyé (obligatoires)
titreTitre du numéro (obligatoire)
publication ou nouvelle_publicationCode d’une publication existante, ou nom d’une nouvelle
parutionMois de parution, AAAA-MM
accesabonnes (par défaut) ou libre
lien_achatLien du bouton de la page publique
telechargement, impressionBooléens. Absents ou null : la règle du titre, sinon téléchargement non et impression oui
adresseFin de l’adresse sur liseuse-pdf.com, ex. escales-n13
couverture_sha256, couverture_tailleUne couverture JPEG envoyée ; sans elle, la page 1 est rendue sous deux minutes ("couverture": "en_preparation")
remplaceIdentifiant d’un numéro dont on remplace le PDF : mêmes adresses, liens et intégrations
publier_leParution programmée, date ISO 8601 à venir, ex. 2026-11-04T08:00:00+01:00 (un an au plus)

Réponse 201 (200 pour un remplacement) : {"numero": {…}, "couverture": "prete" | "en_preparation"}. Les limites de votre formule s’appliquent (402 plan_limit).

PATCH /numeros?id=…

Champs, tous facultatifs : titre, acces, lien_achat (null pour le retirer), en_ligne (true publie aussi un numéro programmé), telechargement, impression (null : comme le titre), publication, publier_le (nouvelle date d’un numéro programmé). GET /numeros indique statut (en_ligne, programme, retire) et publier_le. Les numéros de l’ancienne liseuse se modifient depuis l’espace éditeur (409 not_editable).

GET /statistiques

Paramètres : id (obligatoire), depuis (AAAA-MM-JJ, 30 jours par défaut).

200 OK (valeurs d’exemple)
{
  "id": "liseuse-pdf.com:inklura-escales-n12", "depuis": "2026-09-02",
  "lectures": 412, "lectures_depuis_publication": 1290,
  "par_jour": [{ "jour": "2026-09-30", "lectures": 18 }],
  "temps_moyen_secondes": 402, "lu_jusqu_a_la_fin": 0.58,
  "sources": [{ "source": "direct", "lectures": 260 }, { "source": "votre-site.fr", "lectures": 152 }]
}

GET /compte

Formule, statut, échéance, limites et utilisation : {"compte": {"formule": "pro", "statut": "active", "limites": {…}, "utilisation": {…}}}.

Idempotence

Sur POST /liens et POST /numeros, l’en-tête Idempotency-Key (120 caractères au plus) garantit qu’une requête répétée dans les 24 heures, par exemple après une coupure réseau, renvoie la première réponse sans rien créer de plus. La réponse rejouée porte Idempotent-Replayed: true.

Erreurs, limites et en-têtes

CodeSignification
400Corps illisible ou champ invalide (bad_json, bad_reference…)
401Clé absente, invalide ou révoquée
402Abonnement terminé, ou limite de la formule atteinte
403Permission manquante (forbidden_scope)
404Numéro introuvable pour cette clé
409Adresse déjà prise, ou numéro non modifiable par l’API
413Fichier trop lourd pour votre formule
429Plus de 300 appels par minute (voir Retry-After)

Chaque réponse porte X-Request-Id (à nous donner en cas de question), X-RateLimit-Limit et X-RateLimit-Remaining. Les erreurs ont la forme {"error": {"code": "…", "message": "…"}}.