Inkr API

Erreurs

Format d'erreur normé, codes HTTP, gestion des retries idempotents.

L'API Inkr utilise une enveloppe d'erreur normée inspirée de Stripe. Tous les codes HTTP d'erreur (4xx, 5xx) retournent ce format :

{
  "error": {
    "type": "invalid_request_error",
    "code": "invalid_request",
    "message": "template_id must match the format tpl_<24 base62 chars>"
  }
}

Types d'erreurs

Le champ type ne prend que 4 valeurs.

TypeHTTPQuand
authentication_error401Clé API manquante, invalide ou révoquée.
invalid_request_error400 / 404 / 409 / 422Requête refusée : JSON invalide, schéma Zod refusé, ressource introuvable ou état incompatible.
rate_limit_error429Quota par minute dépassé (header Retry-After).
api_error500Erreur interne Inkr ou dépendance amont.

Pour distinguer précisément un cas, branchez sur le statut HTTP puis sur error.code. Traitez type et code comme des énumérations ouvertes, avec un cas par défaut : une version future peut ajouter des codes sans changer les 4 types.

Codes d'erreur, requête invalide

CodeHTTPSens
missing_api_key401Header Authorization absent.
invalid_api_key401Format invalide, clé inexistante ou révoquée.
invalid_json400Le body n'est pas du JSON valide.
invalid_id400L'identifiant dans l'URL ne respecte pas <préfixe>_<24 base62>.
idempotency_key_required400Header Idempotency-Key absent ou mal formé.
invalid_request422Le body ne correspond pas au schéma. message porte le détail de la première violation.
idempotency_key_reused_with_different_body422Même clé d'idempotence avec un body différent.
invalid_pagination422limit hors de [1, 100] ou curseur illisible.
invalid_status422Valeur de filtre status inconnue.
invalid_created_via422Filtre created_via différent de ui ou api.
invalid_type422Filtre type inconnu sur /v1/events.
invalid_template_id422Filtre template_id mal formé.
invalid_submission_id422Filtre submission_id mal formé.
invalid_email422Filtre email de plus de 320 caractères.
invalid_pdf422Base64 illisible, taille dépassée ou octets magiques %PDF absents.
invalid_pdf_url422L'URL fournie ne renvoie pas un PDF exploitable.
invalid_docx422Le base64 DOCX est illisible.
invalid_field_area422Une zone déborde de la page ou pointe une page inexistante.
invalid_template_tag422Variable {{…}} mal formée ou de type non supporté.
no_tags_found422Aucune variable {{…}} trouvée dans le HTML ou le DOCX.
template_not_found422Le template_id du body n'existe pas dans votre scope.
template_archived422Le template visé est archivé.
submitter_role_not_in_template422Un role de submitters[] ne correspond à aucun rôle du document.
phone_2fa_not_supported422require_phone_2fa: true demandé. Utilisez require_email_2fa.
invalid_events422Liste d'events webhook vide ou contenant un type inconnu.
webhook_url_rejected422URL webhook refusée par le garde-fou SSRF.
webhook_endpoint_limit_reached42225 endpoints webhook actifs déjà enregistrés.
resource_not_found404Ressource inexistante ou hors scope. Le 404 couvre les deux cas volontairement.
submission_not_completed404Audit log demandé sur une submission non completed.
submission_already_finalized409Annulation d'une submission déjà terminée, refusée, expirée ou annulée.
submitter_already_finalized409PATCH sur un submitter déjà signé, refusé ou pré-signé.
slug_already_exists409Un template porte déjà ce slug.
rate_limit_exceeded429Quota par minute dépassé.

Codes d'erreur, côté serveur

CodeHTTPSens
storage_upload_failed500Échec d'envoi du PDF vers le stockage.
template_create_failed500Échec de création du template interne.
html_render_failed500Échec du rendu HTML vers PDF.
docx_convert_failed500Échec de conversion DOCX vers HTML.
db_insert_failed, db_update_failed, db_error500Erreur base de données.
post_create_fetch_failed, post_update_fetch_failed500Objet écrit mais non relu.
internal_inconsistency500Incohérence interne détectée. Retentez.
token_issue_failed500Échec d'émission du token d'embed.
handler_error, server_misconfigured500Exception non gérée ou configuration serveur incomplète.

Codes HTTP

CodeSens
200Succès. Les DELETE renvoient aussi 200 avec un petit objet de confirmation, pas 204.
201Ressource créée (template, submission, endpoint webhook).
400JSON invalide, identifiant d'URL mal formé ou Idempotency-Key manquante.
401Problème d'authentification.
404Ressource inexistante ou hors scope.
409Conflit d'état : objet déjà finalisé, slug déjà pris.
422Schéma refusé ou règle métier violée. C'est le cas le plus fréquent.
429Rate limit dépassé (cf. header Retry-After).
500Erreur Inkr ou upstream. Retry recommandé avec backoff.

Idempotence

Les 5 endpoints de création de document exigent le header Idempotency-Key :

  • POST /v1/templates
  • POST /v1/submissions
  • POST /v1/submissions/from_pdf
  • POST /v1/submissions/from_html
  • POST /v1/submissions/from_docx

Les autres POST (/v1/webhook_endpoints, /v1/webhook_endpoints/{id}/test, /v1/submitters/{id}/embed_token) ne l'exigent pas.

Format accepté : ^[A-Za-z0-9_\-+.:=]{1,255}$. Une UUID v4 fraîche est recommandée.

-H "Idempotency-Key: $(uuidgen)"

Comportement :

SituationRéponse
Premier appel avec cette cléTraité normalement. Réponse mise en cache 24 h.
Même clé, même bodyRéponse rejouée à l'identique avec le header Idempotent-Replayed: true. Rien n'est recréé ni refacturé.
Même clé, body différent422 idempotency_key_reused_with_different_body. Générez une nouvelle clé.
Clé absente ou mal formée400 idempotency_key_required.

La clé est scopée par utilisateur et par route. Réutiliser la même clé sur POST /v1/submissions puis sur POST /v1/submissions/from_pdf ne déclenche donc pas de collision.

Bonnes pratiques retry

async function withRetry(fn, maxAttempts = 3) {
  let lastError
  for (let attempt = 1; attempt <= maxAttempts; attempt++) {
    try {
      return await fn()
    } catch (err) {
      lastError = err
      // Ne retry que sur erreurs réseau, 429 ou 5xx.
      if (err.status && err.status < 500 && err.status !== 429) throw err

      // Backoff exponentiel + jitter
      const delay = Math.min(2 ** attempt * 1000, 10000) + Math.random() * 500
      await new Promise((r) => setTimeout(r, delay))
    }
  }
  throw lastError
}

Ne retry jamais sur 400, 401, 404, 409 ou 422 : le retry produira la même erreur. Retry uniquement sur 429 (avec respect de Retry-After) et sur 5xx, en réutilisant la même Idempotency-Key.