Signlift

Signature Requests

Création et récupération des requêtes de signature électronique.

POST /api/v1/signature_requests

Crée une signature request à partir de documents préalablement uploadés via POST /api/v1/documents.

Tous les champs sont wrappés sous une clé racine signature_request :

{
  "signature_request": {
    /* champs ci-dessous */
  }
}

Body — champs racine

ChampTypeRequisDescription
modestring✓"sequential" ou "parallel".
validity_daysint✓1 à 90.
send_emailboolDéfaut false. Si true, Signlift notifie le premier signataire (mode sequential) ou tous (mode parallel).
identity_declaration_acceptedbool✓ si send_email: trueAtteste que vous avez collecté l'identité des signataires hors-Signlift (exigence eIDAS pour la signature simple). Sans ce flag avec send_email: true, l'API répond 422 identity_declaration_required.
initials_requiredboolParaphes par page. Plans Pro et Enterprise uniquement. Sinon 403 initials_not_available_on_plan.
notify_signers_on_completionboolDéfaut false. E-mail récapitulatif envoyé aux signataires à la complétion.
callback_urlstringURL https qui reçoit les événements terminaux de cette demande — request.completed et request.expired — avec les mêmes headers et la même signature HMAC que le webhook d'application. S'y ajoute, ne le remplace pas. Les événements intermédiaires n'y sont jamais envoyés. Cf. Webhooks.
branding_profile_idintApplique une charte graphique personnalisée au parcours du signataire. Doit correspondre à un profil créé depuis votre organisation (dashboard → Charte). Plans Pro et Enterprise uniquement. Omis ou null → palette Signlift par défaut. Un id qui n'appartient pas à votre organisation est rejeté en 422 validation_error.
signersarray✓Liste des signataires (cf. schéma ci-dessous).
documentsarray✓Liste des documents à signer avec leurs placements de signature (cf. schéma ci-dessous).

Les limites sur le nombre de signataires et de documents dépendent du plan : voir Limites et rate-limits.

Schéma d'un signer (entrée)

{
  "ref": "jeanne",
  "first_name": "Jeanne",
  "last_name": "Dupont",
  "email": "jeanne@example.com",
  "phone": "+33612345678",
  "order": 1,
  "otp_channel": "email"
}
  • ref : identifiant arbitraire choisi par votre code, utilisé pour lier le signataire à ses placements dans documents[].signers[].signer_ref. Non persisté.
  • phone : format E.164 (+CCXXXXXXXXX). Requis si le code part par SMS.
  • order : ordre de signature en mode sequential (ignoré en parallel).
  • otp_channel : email ou sms. Détermine par quel canal arrive le code à usage unique qui authentifie la signature.

sms requiert un phone et un plan Pro ou Enterprise ; email est toujours disponible.

Schéma d'un document (entrée)

{
  "id": 42,
  "signers": [
    {
      "signer_ref": "jeanne",
      "stamps": [
        { "type": "magic_field", "value": { "tag": "[SIG_JEANNE_1]" } },
        { "type": "magic_field", "optional": true, "value": { "tag": "[SIG_JEANNE_2]" } },
        { "type": "coordinates", "value": { "page_number": 3, "x": 100, "y": 120 } }
      ]
    }
  ]
}
  • id : identifiant renvoyé par POST /api/v1/documents.
  • signers : les signataires qui signent ce document, au moins un. Un signataire absent de la liste ne signe pas ce document, mais chaque signataire déclaré à la racine doit en signer au moins un.
  • signer_ref : le ref d'un signataire de la liste racine. Un signataire n'apparaît qu'une fois par document : tous ses tampons vont dans son tableau stamps.
  • stamps : les emplacements où sa signature apparaît sur ce document, de 1 à 10.

Tampons

typevaluePlacement
magic_field{ "tag": "[SIG_JEANNE]" }Le tampon se place juste sous le texte tag, centré sur lui. Le texte doit figurer tel quel dans le PDF, sinon l'API répond 422 (sauf tampon optional).
coordinates{ "page_number", "x", "y", "width", "height" }Position en points PDF, origine en bas à gauche de la page, page_number à partir de 1. width (80 à 400, défaut 200) et height (30 à 160, défaut 80) sont optionnels. Le tampon doit tenir dans la page.

Tampons optionnels

Un gabarit de tampons envoyé sur des PDF qui ne portent pas tous les mêmes tags peut marquer un tampon optional :

  • optional : booléen JSON, false par défaut. À true, un tampon magic_field dont le tag est absent du PDF est ignoré au lieu de faire échouer la demande. Il n'apparaît pas sur le document signé.
  • Le signataire doit malgré tout garder au moins un tampon trouvé sur chaque document qu'il signe : si tous ses tampons y sont introuvables, la demande est refusée en 422.
  • Sans effet sur coordinates : un tampon hors de la page reste refusé.
  • Les tampons optionnels comptent dans la limite de 10 et dans l'unicité des tags.

Un placement invalide est refusé en 422 validation_error, et aucune demande n'est créée :

  • stamps absent ou vide, ou plus de 10 tampons pour un signataire sur un document ;
  • un signataire listé deux fois sur un même document ;
  • un même tag utilisé deux fois par un signataire sur un document ;
  • un tag introuvable dans le PDF sur un tampon qui n'est pas optional, une page inexistante, un tampon qui déborde de la page ;
  • aucun tampon trouvé pour un signataire sur un document, quand tous ses tampons y sont optional ;
  • un optional qui n'est pas un booléen JSON ("true" ou null sont refusés) ;
  • un signer_ref qui ne correspond à aucun signataire.

Charte graphique du parcours

Les organisations sur les plans Pro et Enterprise peuvent personnaliser les couleurs du parcours de signature (fond, texte, accentuation). Les profils sont créés et gérés depuis le dashboard, dans Charte au niveau de l'organisation — l'API n'expose que leur lecture, via GET /api/v1/branding_profiles, pas leur création. Limite : 2 profils sur Pro, 10 sur Enterprise.

Pour appliquer un profil à une demande, transmettez son identifiant dans branding_profile_id :

curl https://app.signlift.eu/api/v1/signature_requests \
  -H "X-Api-Key: $SIGNLIFT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "signature_request": {
      "mode": "parallel",
      "validity_days": 30,
      "branding_profile_id": 7,
      "signers": [ /* … */ ],
      "documents": [ /* … */ ]
    }
  }'

Si l'identifiant n'appartient pas à votre organisation, l'API répond 422 validation_error. Les demandes créées sans branding_profile_id conservent l'apparence générique Signlift.

L'objet branding_profile est renvoyé dans la réponse de tous les endpoints qui retournent une signature_request (cf. ci-dessous), ou null quand la demande utilise la palette par défaut.

Exemple minimal

curl https://app.signlift.eu/api/v1/signature_requests \
  -H "X-Api-Key: $SIGNLIFT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "signature_request": {
      "mode": "sequential",
      "validity_days": 30,
      "send_email": true,
      "identity_declaration_accepted": true,
      "signers": [
        {
          "ref": "jeanne",
          "first_name": "Jeanne",
          "last_name": "Dupont",
          "email": "jeanne@example.com",
          "order": 1
        }
      ],
      "documents": [
        {
          "id": 42,
          "signers": [
            {
              "signer_ref": "jeanne",
              "stamps": [{ "type": "magic_field", "value": { "tag": "[SIG_JEANNE]" } }]
            }
          ]
        }
      ]
    }
  }'

Pour un payload complet (mode parallel, placements par coordonnées, paraphes), utilisez le playground interactif.

Réponse 201

{
  "id": 42,
  "mode": "sequential",
  "status": "pending",
  "validity_days": 30,
  "initials_required": false,
  "notify_signers_on_completion": false,
  "expires_at": "2026-06-16T15:00:00Z",
  "created_at": "2026-05-17T15:00:00Z",
  "document_ids": [42],
  "signers": [
    {
      "id": 1768,
      "first_name": "Jeanne",
      "last_name": "Dupont",
      "full_name": "Jeanne Dupont",
      "email": "jeanne@example.com",
      "order": 1,
      "status": "pending",
      "signed_at": null,
      "signing_url": "https://app.signlift.eu/sign/eyJhbGciOiJIUzI1NiJ9..."
    }
  ],
  "branding_profile": {
    "id": 7,
    "name": "Marque Acme",
    "background_color": "#f5f0e6",
    "text_color": "#173039",
    "accent_color": "#202c90"
  }
}

branding_profile vaut null quand la demande utilise la palette par défaut.

Le statut du signer est pending à la réponse synchrone — il passe à notified une fois l'e-mail envoyé (job asynchrone).

Le champ signing_url est l'URL absolue à transmettre au signataire — voir Authentification et Intégration iframe.

Le champ download_urls n'est pas présent à la création — il apparaît uniquement sur le GET ci-dessous, et uniquement lorsque la signature request est completed.

GET /api/v1/signature_requests

Liste paginée de vos demandes de signature. C'est le seul moyen de retrouver vos enveloppes sans en avoir conservé les identifiants — rejouer une archive, réconcilier après un incident, alimenter un tableau de bord.

Enveloppe, pagination et filtres : voir Collections paginées. Le filtre status accepte pending, completed et expired.

Exemple

curl "https://app.signlift.eu/api/v1/signature_requests?status=completed&created_after=2026-05-01" \
  -H "X-Api-Key: $SIGNLIFT_API_KEY"

Réponse 200

{
  "data": [
    {
      "id": 42,
      "status": "completed",
      "finalized": true,
      "mode": "sequential",
      "expires_at": "2026-06-16T15:00:00Z",
      "created_at": "2026-05-17T15:00:00Z",
      "document_ids": [7],
      "signers": []
    }
  ],
  "pagination": { "page": 1, "limit": 20, "count": 1, "pages": 1 }
}

Chaque entrée reprend la sérialisation du GET unitaire ci-dessous, à une exception près : download_urls n'apparaît jamais dans la liste, même pour une demande finalisée. Le générer coûterait une URL S3 présignée par document, multipliée par le nombre de documents de chaque enveloppe de la page. Appelez le GET unitaire pour les obtenir.

GET /api/v1/signature_requests/{id}

Récupère l'état actuel d'une signature request.

Statuts possibles

StatusSignification
pendingAu moins un signataire n'a pas encore signé.
completedTous les signataires ont signé. Le scellement suit, voir finalized.
expiredvalidity_days dépassé sans complétion.

Les signataires individuels ont leur propre cycle de statut (pending → notified → signed), exposé dans signers[].status.

Réponse 200 — signature complétée

{
  "id": 42,
  "mode": "sequential",
  "status": "completed",
  "finalized": true,
  "validity_days": 30,
  "initials_required": false,
  "notify_signers_on_completion": false,
  "expires_at": "2026-06-16T15:00:00Z",
  "created_at": "2026-05-17T15:00:00Z",
  "document_ids": [42],
  "signers": [
    {
      "id": 1768,
      "first_name": "Jeanne",
      "last_name": "Dupont",
      "full_name": "Jeanne Dupont",
      "email": "jeanne@example.com",
      "order": 1,
      "status": "signed",
      "signed_at": "2026-05-17T15:12:43Z",
      "signing_url": null
    }
  ],
  "branding_profile": null,
  "download_urls": [
    {
      "document_id": 42,
      "signed_url": "https://s3.eu-west-1.amazonaws.com/...?X-Amz-Signature=...",
      "certificate_url": "https://s3.eu-west-1.amazonaws.com/...?X-Amz-Signature=...",
      "expires_in": 900
    }
  ]
}

Les URLs signed_url et certificate_url sont des URLs S3 présignées valides pendant expires_in secondes (900 = 15 minutes). Pour les récupérer à nouveau, rappelez ce même endpoint.

status et finalized ne disent pas la même chose

status: "completed" signifie que le dernier signataire a signé. Le scellement des PDF et l'émission du dossier de preuve se font juste après, de façon asynchrone.

finalized passe à true quand tous les artefacts sont disponibles, et download_urls n'apparaît pas avant. C'est donc finalized qu'il faut attendre, pas status : une intégration qui déclenche son téléchargement sur completed reçoit une réponse sans URLs.

Le dossier de preuve

C'est un PDF distinct du document signé, scellé lui aussi, unique par demande : avec plusieurs documents, chaque entrée de download_urls porte la même certificate_url, un seul téléchargement suffit.

Il contient :

  • les signataires, avec le canal d'authentification utilisé (SMS ou e-mail) et la destination exacte à laquelle le code à usage unique a été envoyé ;
  • pour chaque document : son nom, son nombre de pages, et deux empreintes SHA-256, celle du fichier déposé et celle du fichier signé ;
  • le journal d'audit horodaté à la milliseconde, fuseau inclus, chaque ligne attribuée nominativement à son signataire ;
  • l'horodatage RFC 3161 du sceau, avec le nom de l'autorité qui l'a délivré.

La version exploitable par une machine du même journal est disponible via GET /api/v1/signature_requests/:id/audit_logs.

On this page