Documentation API

API BizSign pour intégrateurs

Utilisez l'API native BizSign ou les couches de compatibilité DocuSign et YouSign avec les mêmes identifiants OAuth2.

Créer une application Authentification Scopes Limites et quotas Erreurs Révocation Référence OpenAPI Webhooks

1. Créer une application

Un administrateur d'organisation crée et gère ses identifiants depuis API & Développeurs. Le secret n'est affiché qu'une fois : copiez-le immédiatement dans votre coffre de secrets.

Vous n'avez pas encore de compte ou l'accès API n'est pas disponible selon votre offre ? Le formulaire pour les prospects permet de décrire votre projet à l'équipe BizSign.

Tester une première demande

URL de cet environnement : https://bizsign.fr. Le titulaire crée son compte, termine son enrôlement, puis reçoit l’offre de test sur son organisation. Cette offre doit autoriser l’accès API, la création d’applications, les scopes nécessaires, le niveau de signature et les volumes utilisés. La gratuité seule n’ouvre pas ces droits.

L’exemple utilise la compatibilité YouSign et un PDF de test. Renseignez les variables indiquées au début du script, puis exécutez-le dans votre terminal. Utilisez une adresse et un mobile de test sous votre contrôle. Le niveau electronic_signature correspond à la Signature Vérifiée de BizSign ; l’offre doit l’autoriser et prévoir des actes pour ce niveau. L’activation consomme les unités selon votre offre. L’activation YouSign ne déclenche actuellement pas d’email d’invitation ; le script récupère le lien de signature pour l’ouvrir dans votre plateforme. Le secret reste côté serveur ; ne l’intégrez pas au JavaScript du navigateur.

#!/usr/bin/env bash
# Exemple de test : crée et active une demande réelle, avec un destinataire de test.
# Prérequis : bash, curl, jq, base64 ; un PDF et une application autorisée par l'offre.
set -euo pipefail
: "${BASE_URL:?Renseigner l’URL BizSign de votre environnement}"
: "${CLIENT_ID:?Renseigner le Client ID}"
: "${CLIENT_SECRET:?Renseigner le secret depuis votre gestionnaire de secrets}"
: "${TEST_SIGNER_EMAIL:?Renseigner une adresse de test sous votre contrôle}"
: "${TEST_SIGNER_PHONE:?Renseigner le mobile de test au format international}"
: "${PDF_PATH:?Renseigner le chemin d’un PDF de test}"
BASE_URL="${BASE_URL%/}"
export CLIENT_ID CLIENT_SECRET TEST_SIGNER_EMAIL TEST_SIGNER_PHONE

# Le secret passe dans le corps, sans interpolation dans une commande shell.
TOKEN=$(jq -nr '
  "grant_type=client_credentials&client_id=" + (env.CLIENT_ID|@uri)
  + "&client_secret=" + (env.CLIENT_SECRET|@uri)
  + "&scope=" + ("signature:read signature:write documents:read documents:write"|@uri)
' | curl --fail-with-body --silent --show-error \
  -H 'Content-Type: application/x-www-form-urlencoded' --data-binary @- \
  "$BASE_URL/api/compat/oauth/token" | jq -er '.access_token')
unset CLIENT_SECRET

api() {
  curl --fail-with-body --silent --show-error \
    -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' "$@"
}
API_BASE="$BASE_URL/api/compat/yousign/v3"
REQUEST_ID=$(api -X POST "$API_BASE/signature_requests" \
  --data '{"name":"Test intégration BizSign","delivery_mode":"none"}' | jq -er '.id')
DOCUMENT_ID=$(base64 < "$PDF_PATH" | tr -d '\n' \
  | jq -Rs '{file:.,file_name:"test.pdf",nature:"signable_document"}' \
  | api -X POST "$API_BASE/signature_requests/$REQUEST_ID/documents" \
    --data-binary @- | jq -er '.id')
export DOCUMENT_ID
SIGNER_ID=$(jq -n '{
  info:{first_name:"Test",last_name:"Intégration",email:env.TEST_SIGNER_EMAIL,phone_number:env.TEST_SIGNER_PHONE},
  signature_level:"electronic_signature",
  signature_authentication_mode:"otp_sms",
  fields:[{document_id:env.DOCUMENT_ID,type:"signature",page:1,x:50,y:100,width:180,height:60}]
}' | api -X POST "$API_BASE/signature_requests/$REQUEST_ID/signers" \
  --data-binary @- | jq -er '.id')

# L’activation réserve les unités selon votre offre. Ce n’est pas une simulation.
api -X POST "$API_BASE/signature_requests/$REQUEST_ID/activate" > /dev/null
# Ouvrir signature_link dans un navigateur pour signer le PDF de test.
api "$API_BASE/signature_requests/$REQUEST_ID/signers/$SIGNER_ID" | jq '{status,signature_link}'
# Après signature : consulter l’état, puis télécharger le PDF.
api "$API_BASE/signature_requests/$REQUEST_ID" | jq '{id,status}'
# Quand status vaut done :
# api "$API_BASE/signature_requests/$REQUEST_ID/documents/$DOCUMENT_ID/download" -o signe.pdf

2. Authentification OAuth2

L'API utilise le flux OAuth2 client_credentials. Le scope accordé est l'intersection entre la demande, les droits de l'application et ceux disponibles selon votre offre.

curl -X POST https://bizsign.fr/api/compat/oauth/token \
  -d "grant_type=client_credentials" \
  -d "client_id=VOTRE_CLIENT_ID" \
  -d "client_secret=VOTRE_CLIENT_SECRET" \
  -d "scope=signature:read signature:write"

Envoyez ensuite Authorization: Bearer <access_token> sur chaque appel natif ou compatible. Une demande sans scope disponible renvoie invalid_scope.

3. Scopes

ScopeAutorise
signature:readLire les demandes de signature et les enveloppes
signature:writeCréer, envoyer et annuler des demandes de signature
documents:readLire et télécharger les documents
documents:writeAjouter et remplacer des documents
templates:readLire les modèles
templates:writeCréer et modifier les modèles
contacts:readLire les contacts
webhooks:readLire les souscriptions webhooks
webhooks:writeCréer et supprimer des souscriptions webhooks
usage:readConsulter l'utilisation de l'API

Les anciens scopes de compatibilité restent acceptés : envelopes:read → signature:read, envelopes:write → signature:write, signature_requests:read → signature:read, signature_requests:write → signature:write .

4. Limites et quotas

  • Le débit est plafonné selon votre offre, par organisation et par application.
  • Les réponses exposent X-RateLimit-Limit, X-RateLimit-Remaining et X-RateLimit-Reset.
  • Le quota mensuel est partagé par les applications de l'organisation ; ses en-têtes sont X-Quota-Limit, X-Quota-Used et X-Quota-Reset.
  • Un refus temporaire fournit Retry-After. Selon votre offre, le dépassement mensuel est bloqué ou facturé.

Consultez les compteurs et l'historique dans Consommation.

5. Erreurs du péage API

StatutCodeRéponse
403insufficient_scope{"error":"insufficient_scope","required":[…]} et WWW-Authenticate
403api_access_requires_business_plan{"detail":"api_access_requires_business_plan"}
429rate_limitedInclut retry_after et les en-têtes de débit.
429quota_exceededInclut quota, used, resets_at et les en-têtes de quota.

6. Révocation

Révoquez un jeton devenu inutile ou compromis. Après authentification du client, la réponse est idempotente, même si le jeton est déjà inconnu ou révoqué.

curl -X POST https://bizsign.fr/api/compat/oauth/revoke \
  -d "token=VOTRE_ACCESS_TOKEN" \
  -d "token_type_hint=access_token" \
  -d "client_id=VOTRE_CLIENT_ID" \
  -d "client_secret=VOTRE_CLIENT_SECRET"

Renouveler le secret dans API & Développeurs invalide immédiatement tous les tokens déjà émis pour l'application.

7. Référence des opérations

API native

Workflows, documents, modèles, contacts et vérification d'horodatage sous /api/v1.

Compat DocuSign

Base /api/compat/docusign/v2.1/accounts/{account_id}.

Compat YouSign

Base /api/compat/yousign/v3.

Schéma OpenAPI public

Le document JSON ne contient que les routes destinées aux intégrateurs et indique x-required-scopes pour chaque opération protégée.

Télécharger /api/openapi.json

Compatibilité et refus à l’envoi

La couverture DocuSign et YouSign est partielle. Les tableaux ci-dessous sont publiés depuis la matrice versionnée du produit. Un endpoint YouSign absent de cette liste retourne 404. Une opération indiquée 501 n’est pas implémentée. Les refus de contrat ne consomment aucune unité ; corrigez le droit ou le quota avant de réessayer.

Authentification et droits du forfait

CauseStatutYouSign typeDocuSign errorCode
Niveau non autorisé par le contrat403forbiddenPLAN_LIMIT_REACHED
Quota mensuel d'actes atteint pour ce niveau403forbiddenSIGNATURE_ACT_QUOTA_REACHED
Quota mensuel de Biz atteint400bad_requestQUOTA_EXCEEDED
Facture échue, nouvelles demandes suspendues402payment_requiredPAYMENT_REQUIRED
Engagement de volume épuisé402payment_requiredPAYMENT_REQUIRED

DocuSign eSignature REST v2.1

EndpointMéthodeStatutNotes
/envelopesGETSupportéFiltres statut / dates / texte, pagination
/envelopesPOSTSupportéDocuments, recipients et tabs fournis à la création
/envelopes/{id}GETSupporté
/envelopes/{id}PUTSupportéEnvoi (sent) et annulation (voided)
/envelopes/{id}/documentsGETSupportéInclut le document virtuel combined
/envelopes/{id}/documentsPUTNon implémenté (501)Fournir tous les documents au POST /envelopes
/envelopes/{id}/documents/{docId}GETSupportéTéléchargement PDF
/envelopes/{id}/recipientsGETSupporté
/envelopes/{id}/recipientsPOSTNon implémenté (501)Fournir tous les recipients au POST /envelopes
/envelopes/{id}/recipientsPUTNon implémenté (501)
/envelopes/{id}/recipients/{rid}/tabsGETSupporté
/envelopes/{id}/recipients/{rid}/tabsPOSTNon implémenté (501)Fournir les tabs au POST /envelopes
/envelopes/{id}/recipients/{rid}/tabsPUTNon implémenté (501)
/envelopes/{id}/recipients/{rid}/tabsDELETENon implémenté (501)
/envelopes/{id}/views/recipientPOSTSupporté (partiel)Retourne une URL tokenisée réelle vers la cérémonie de signature BizSign (/sign/{token}). Limite : pas de redirection vers returnUrl en fin de cérémonie, et authenticationMethod n'est pas appliqué.

YouSign API v3

EndpointMéthodeStatutNotes
/signature_requestsPOSTSupportéCréation en statut draft
/signature_requests/{id}GETSupporté
/signature_requests/{id}/activatePOSTSupporté
/signature_requests/{id}/cancelPOSTSupporté
/signature_requests/{id}/documentsGETSupporté
/signature_requests/{id}/documentsPOSTSupportéContenu base64
/signature_requests/{id}/documents/{docId}DELETESupportéSuppression réelle (document + champs + fichier), requêtes draft uniquement
/signature_requests/{id}/documents/{docId}/downloadGETSupportéPDF final de la pièce après finalisation ; 409 en cours, 404 si le fichier manque
/signature_requests/{id}/documents/{docId}/fieldsGETSupporté
/signature_requests/{id}/signersPOSTSupportéCréation d'utilisateur invité si nécessaire
/signature_requests/{id}/signers/{signerId}GETSupporté
/signature_requests/{id}/signers/{signerId}DELETESupportéSuppression réelle (signataire + champs assignés), requêtes draft uniquement
/webhooksPOST / GETSupportéAbonnements globaux par client API
/webhooks/{id}DELETESupportéDésactivation (soft delete)

Recette du parcours client : états, fichiers, appels et reprise (#330)

État ou événementFichiers disponiblesQuiAppelReprise
Brouillon créé, documents et participants ajoutésOriginaux seulementApplication, scopes signature:write, documents:writePOST …/signature_requests, …/documents, …/signersRejouer l’appel en échec ; rien n’est réservé avant l’envoi
Envoi explicite (activate ou status: sent)OriginauxApplication, signature:writePOST …/signature_requests/{id}/activateUn refus 403/402 (PLAN_LIMIT_REACHED, SIGNATURE_ACT_QUOTA_REACHED, CONSENT_REQUIRED, impayé) ne consomme rien : corriger la cause, rejouer
signature_request.activated reçuOriginaux ; signature_link du participant en attenteApplication, signature:readGET …/signers/{signer_id}Notification manquée : relire le détail de la demande
signer.done reçu, status encore ongoingOriginaux ; PDF de preuve provisoireApplication, signature:read + documents:readGET /api/v1/workflows/{id}/proof/status, …/proof?format=pdfAttendre les autres participants
status=done, finalisation en coursPDF de preuve ; PDF finaux pas encoreApplication, documents:readGET …/documents/{document_id}/download → 409 DOCUMENT_NOT_READYAttendre Retry-After secondes, rejouer le téléchargement
signature_request.done reçu (jalon EMAILS)Un PDF final par document ; PDF de preuve définitifApplication, documents:readGET …/documents/{document_id}/download, un appel par documentNotification manquée ou perdue : le téléchargement se relit à tout moment ; répétée : dédupliquer sur l’identifiant d’événement
Finalisation en échecPDF de preuve ; finaux indisponiblesApplicationMême appel → 409 DOCUMENT_FINALIZATION_FAILEDReprise côté BizSign (support) ; ne jamais substituer un original
Ancrage soumis, non confirmé (ots_state=initial)OTS initial, archive ZIP (PDF, OTS, ancrage.json, README.txt, jetons .tst)Application, signature:read + documents:readGET …/proof?format=ots, …/proof?format=zip409 OTS_NOT_AVAILABLE tant que l’ancrage n’a pas été soumis : relire proof/status
signature_request.bitcoin_confirmed reçu (bitcoin_confirmed=true)OTS complété, archive à jourApplicationRetélécharger ots et zip ; ots_sha256 a changéNotification manquée : relire proof/status ; aucune renotification rétroactive
Archive incomplètePDF et OTS séparésApplication…/proof?format=zip → 409 PROOF_ARCHIVE_INCOMPLETEConserver PDF et OTS ; signaler la demande au support
Demande d’une autre organisation, document inconnuAucun—Toute route → 404Vérifier l’organisation de l’application ; jamais de repli

Recette complète du parcours client

Ce second script enchaîne tout le parcours que votre plateforme devra tenir : jeton, abonnement aux notifications, demande à deux documents distincts, participant, envoi explicite, signature dans le parcours réel, attente de la fin, téléchargement de chaque PDF final avec traitement des réponses temporaires, état et exports de preuve, observation distincte de la confirmation Bitcoin, et reprise après une notification manquée ou répétée. Il consigne un journal sans secret ni donnée personnelle, avec la version testée.

Trois états à ne jamais confondre : status=done (toutes les signatures sont posées), PDF final disponible (finalisation, scellement et horodatage terminés, annoncés par signature_request.done) et bitcoin_confirmed=true (ancrage vérifié, annoncé par signature_request.bitcoin_confirmed, sans délai garanti). Le tableau Recette du parcours client de la rubrique compatibilité donne, pour chaque état, les fichiers disponibles, qui peut les récupérer, l’appel à faire et la reprise.

#!/usr/bin/env bash
# Recette du parcours client BizSign par l’API (#330) : jeton, demande à deux
# documents, participant, envoi explicite, signature dans le parcours réel,
# notifications, PDF finaux, preuves, confirmation Bitcoin, reprise.
# Prérequis : bash, curl, jq, base64, sha256sum ; deux PDF de test sans donnée
# personnelle ; une application autorisée par l’offre (scopes ci-dessous).
# Rien n’est simulé : l’envoi réserve les unités selon votre offre.
set -euo pipefail
: "${BASE_URL:?Renseigner l’URL BizSign de votre environnement}"
: "${CLIENT_ID:?Renseigner le Client ID}"
: "${CLIENT_SECRET:?Renseigner le secret depuis votre gestionnaire de secrets}"
: "${TEST_SIGNER_EMAIL:?Renseigner une adresse de test sous votre contrôle}"
: "${TEST_SIGNER_PHONE:?Renseigner le mobile de test au format international}"
: "${PDF_PATH:?Renseigner le chemin du premier PDF de test}"
: "${PDF2_PATH:?Renseigner le chemin du second PDF de test}"
WEBHOOK_URL="${WEBHOOK_URL:-}"          # facultatif : URL HTTPS de votre récepteur
POLL_SECONDS="${POLL_SECONDS:-30}"      # intervalle de relance de l’état
OUT_DIR="${OUT_DIR:-recette-$(date -u +%Y%m%dT%H%M%SZ)}"
BASE_URL="${BASE_URL%/}"
mkdir -p "$OUT_DIR"
export CLIENT_ID CLIENT_SECRET TEST_SIGNER_EMAIL TEST_SIGNER_PHONE

log() { printf '%s %s\n' "$(date -u +%H:%M:%S)" "$*" >&2; }
note() { # consigne une observation, jamais un secret ni une donnée personnelle
  jq -n --arg step "$1" --arg value "$2" --arg at "$(date -u +%FT%TZ)" \
    '{at:$at,step:$step,value:$value}' >> "$OUT_DIR/journal.jsonl"
}

# 1. Jeton — le secret passe dans le corps, jamais dans une ligne de commande.
TOKEN=$(jq -nr '
  "grant_type=client_credentials&client_id=" + (env.CLIENT_ID|@uri)
  + "&client_secret=" + (env.CLIENT_SECRET|@uri)
  + "&scope=" + ("signature:read signature:write documents:read documents:write webhooks:read webhooks:write"|@uri)
' | curl --fail-with-body --silent --show-error \
  -H 'Content-Type: application/x-www-form-urlencoded' --data-binary @- \
  "$BASE_URL/api/compat/oauth/token" | jq -er '.access_token')
unset CLIENT_SECRET
note "token" "obtenu"

api() { curl --silent --show-error -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' "$@"; }
must() { api --fail-with-body "$@"; }
YS="$BASE_URL/api/compat/yousign/v3"

# Version testée : le contrat OpenAPI public porte la version du produit.
VERSION=$(curl --silent --fail "$BASE_URL/api/openapi.json" | jq -r '.info.version // "inconnue"')
note "version" "$VERSION"

# 2. Notifications — les trois événements qui rythment le parcours. Extension
#    BizSign : signature_request.bitcoin_confirmed n’existe pas chez YouSign.
if [ -n "$WEBHOOK_URL" ]; then
  export WEBHOOK_URL
  WEBHOOK_ID=$(jq -n '{url:env.WEBHOOK_URL,
    events:["signature_request.activated","signature_request.done","signature_request.bitcoin_confirmed"]}' \
    | must -X POST "$YS/webhooks" --data-binary @- | jq -er '.id')
  note "webhook" "abonnement $WEBHOOK_ID"
fi

# 3. Demande — deux documents DISTINCTS, un participant avec un champ sur chacun.
REQUEST_ID=$(must -X POST "$YS/signature_requests" \
  --data '{"name":"Recette BizSign — deux documents","delivery_mode":"none"}' | jq -er '.id')
note "request" "$REQUEST_ID"
add_document() { # $1 chemin, $2 nom publié
  base64 < "$1" | tr -d '\n' \
    | jq -Rs --arg name "$2" '{file:.,file_name:$name,nature:"signable_document"}' \
    | must -X POST "$YS/signature_requests/$REQUEST_ID/documents" --data-binary @- | jq -er '.id'
}
DOC1=$(add_document "$PDF_PATH" "recette-1.pdf")
DOC2=$(add_document "$PDF2_PATH" "recette-2.pdf")
export DOC1 DOC2
SIGNER_ID=$(jq -n '{
  info:{first_name:"Test",last_name:"Recette",email:env.TEST_SIGNER_EMAIL,phone_number:env.TEST_SIGNER_PHONE},
  signature_level:"electronic_signature",
  signature_authentication_mode:"otp_sms",
  fields:[{document_id:env.DOC1,type:"signature",page:1,x:50,y:100,width:180,height:60},
          {document_id:env.DOC2,type:"signature",page:1,x:50,y:100,width:180,height:60}]
}' | must -X POST "$YS/signature_requests/$REQUEST_ID/signers" --data-binary @- | jq -er '.id')

# 4. Envoi EXPLICITE — c’est l’activation qui engage et réserve les unités.
#    Un refus de contrat (403 PLAN_LIMIT_REACHED, SIGNATURE_ACT_QUOTA_REACHED,
#    CONSENT_REQUIRED…) sort ici, lisible, et ne consomme rien.
must -X POST "$YS/signature_requests/$REQUEST_ID/activate" > /dev/null
note "activate" "envoyée"

# 5. Signature dans le parcours réel : ouvrir le lien dans un navigateur, sur
#    le mobile de test, et signer les deux documents (code SMS).
must "$YS/signature_requests/$REQUEST_ID/signers/$SIGNER_ID" \
  | jq -r '"Lien de signature : \(.signature_link)\nExpire le : \(.signature_link_expiration_date)"' >&2

# 6. Attendre la fin : ici par relance de l’état ; en production, par le
#    webhook signature_request.done. Les deux mènent au même téléchargement.
#    Signature terminée (status=done) ≠ PDF disponible ≠ Bitcoin confirmé.
until [ "$(must "$YS/signature_requests/$REQUEST_ID" | jq -r '.status')" = "done" ]; do
  log "en attente de la signature… (relance dans ${POLL_SECONDS}s)"; sleep "$POLL_SECONDS"
done
note "status" "done"

# 7. Chaque PDF final, par identifiant. 409 DOCUMENT_NOT_READY + Retry-After :
#    la finalisation est en cours, on attend le délai annoncé puis on rejoue.
#    409 DOCUMENT_FINALIZATION_FAILED : une reprise côté BizSign est nécessaire.
download_final() { # $1 id document, $2 fichier de sortie
  local code headers="$OUT_DIR/headers.tmp"
  while :; do
    code=$(api -D "$headers" -o "$2" -w '%{http_code}' \
      "$YS/signature_requests/$REQUEST_ID/documents/$1/download")
    case "$code" in
      200) sha256sum "$2" | cut -d' ' -f1; return 0 ;;
      409) if jq -e '.code=="DOCUMENT_NOT_READY"' "$2" > /dev/null 2>&1; then
             local wait; wait=$(grep -i '^Retry-After:' "$headers" | tr -dc '0-9'); wait="${wait:-$POLL_SECONDS}"
             log "document $1 : finalisation en cours, nouvel essai dans ${wait}s"; sleep "$wait"
           else
             log "document $1 : $(jq -r '.code // .detail' "$2") — reprise nécessaire, voir le support"; return 1
           fi ;;
      *) log "document $1 : HTTP $code"; cat "$2" >&2; return 1 ;;
    esac
  done
}
note "pdf1_sha256" "$(download_final "$DOC1" "$OUT_DIR/recette-1-signe.pdf")"
note "pdf2_sha256" "$(download_final "$DOC2" "$OUT_DIR/recette-2-signe.pdf")"

# 8. Preuves — état d’abord, puis exports. Le PDF de preuve existe dès la fin ;
#    l’OTS et l’archive attendent le premier ancrage ; bitcoin_confirmed est
#    une observation DISTINCTE, souvent plus tardive (aucun délai garanti).
V1="$BASE_URL/api/v1/workflows/$REQUEST_ID"
STATUS=$(must "$V1/proof/status")
echo "$STATUS" | jq '{documents_state,proof_state,ots_state,public_anchor_status,bitcoin_confirmed}' >&2
note "proof_status" "$(echo "$STATUS" | jq -c '{documents_state,proof_state,ots_state,bitcoin_confirmed}')"
must "$V1/proof?format=pdf" -o "$OUT_DIR/preuve.pdf"
for fmt in ots zip; do
  code=$(api -o "$OUT_DIR/preuve.$fmt" -w '%{http_code}' "$V1/proof?format=$fmt")
  [ "$code" = 200 ] && note "proof_$fmt" "téléchargé" || note "proof_$fmt" "HTTP $code $(jq -r '.detail' "$OUT_DIR/preuve.$fmt" 2>/dev/null)"
done

# 9. Reprise. Notification manquée : l’état ci-dessus se relit à tout moment,
#    aucun événement n’est nécessaire pour récupérer les fichiers. Notification
#    reçue deux fois : dédupliquer sur l’identifiant d’événement. Confirmation
#    Bitcoin attendue : relire proof/status jusqu’à bitcoin_confirmed=true,
#    puis retélécharger l’OTS et l’archive (l’empreinte ots_sha256 change).
if [ "$(echo "$STATUS" | jq -r '.bitcoin_confirmed')" != "true" ]; then
  log "Bitcoin non confirmé à cet instant : relire $V1/proof/status plus tard, puis reprendre l’OTS et l’archive."
fi
[ -n "${WEBHOOK_ID:-}" ] && must -X DELETE "$YS/webhooks/$WEBHOOK_ID" > /dev/null
rm -f "$OUT_DIR/headers.tmp"
log "Recette terminée. Journal sans secret : $OUT_DIR/journal.jsonl"

Récupérer les documents

Téléchargez chaque document par son identifiant. Après finalisation, chaque pièce principale fournit son propre PDF final scellé et horodaté. Les annexes restent leurs fichiers d’origine. La confirmation Bitcoin n’est pas nécessaire pour récupérer les PDF.

Le code est dans code pour YouSign et errorCode pour DocuSign. Avant la fin des signatures, hors finalisation en cours, le téléchargement retourne l’original. Le statut « terminé » peut précéder la finalisation : traitez la réponse du téléchargement. Le webhook de fin est enregistré après la préparation des PDF, leur scellement, leur horodatage et la preuve privée. Les fichiers peuvent alors être récupérés, même si un email de fin doit être repris. Il n’attend pas Bitcoin.

Récupérer les preuves

Ces routes natives BizSign utilisent le même jeton applicatif, y compris pour une demande créée avec YouSign ou DocuSign. Accordez les scopes signature:read et documents:read. L’application accède au dossier global des demandes de son organisation ; une session de signataire n’y donne pas accès.

proof_state vaut unavailable, provisional ou definitive. Le PDF provisoire porte un filigrane. Le dossier devient définitif après les étapes cryptographiques, même si un email est en reprise. documents_state indique pending, ready ou failed.

ots_state vaut unavailable, initial ou completed. Une preuve initiale n’est pas une confirmation Bitcoin. Consultez bitcoin_confirmed et public_anchor_status. Quand ots_sha256 change, téléchargez de nouveau l’OTS et l’archive avec les liens de downloads. Ces liens nécessitent toujours votre jeton.

Un export indisponible répond 409 avec detail: PROOF_NOT_AVAILABLE avant la première participation ou detail: OTS_NOT_AVAILABLE pour l’OTS et l’archive encore absents. Un ZIP dont un jeton d’horodatage manque ou ne correspond pas à l’ancrage répond detail: PROOF_ARCHIVE_INCOMPLETE (409) ; les exports PDF et OTS séparés restent accessibles. Le PDF reste téléchargeable sans OTS. Une demande inaccessible répond 404. Abonnez-vous aussi à la confirmation Bitcoin décrite ci-dessous pour récupérer la preuve complétée.

Le ZIP conserve les jetons d’origine dans horodatages/*.tst (DER, CMS TimeStampToken). Le tableau timestamp_tokens de ancrage.json associe chaque fichier à son document et aux empreintes SHA-256 du PDF final et du jeton. README.txt explique la contre-vérification avec OpenSSL ; la confiance dans les certificats de l’autorité TSA doit être établie indépendamment. Une archive ancienne sans manifeste d’horodatage exploitable répond aussi PROOF_ARCHIVE_INCOMPLETE.

8. Webhooks

Les souscriptions compatibles YouSign sont gérées sous /api/compat/yousign/v3/webhooks avec les scopes webhooks:read et webhooks:write.

Lorsqu'un secret est configuré, BizSign signe le corps exact avec HMAC-SHA256 dans X-Yousign-Signature-256. La signature HMAC des notifications compatibles DocuSign n'est pas encore disponible.

La confirmation Bitcoin dispose de deux extensions propres à BizSign : signature_request.bitcoin_confirmed pour une souscription YouSign (ajoutez ce nom à events) et envelope-bitcoin-confirmed pour DocuSign (ajoutez envelopeEventStatusCode: bitcoin-confirmed à eventNotification.envelopeEvents lors de la création). Ces noms ne sont pas des événements natifs des fournisseurs.

Cet événement est enregistré uniquement après vérification de l’attestation OTS et du bloc Bitcoin. Le bloc proof se trouve dans data.signature_request pour YouSign ou data.envelopeSummary pour DocuSign. Il fournit bitcoin_confirmed: true, ots_state: completed, ots_sha256, bitcoin_block_height, bitcoin_block_hash, confirmed_at (UTC), request_id, status_url et downloads (PDF, OTS, ZIP). Les liens sont relatifs à BizSign et nécessitent votre jeton avec les scopes signature:read et documents:read. Téléchargez et conservez la nouvelle version de l’OTS et de l’archive ; aucun fichier n’est joint au webhook. Une souscription créée après la confirmation ne reçoit pas d’événement rétroactif : consultez alors l’état. Bitcoin ne bloque pas la livraison des PDF finaux et aucun délai de confirmation n’est garanti.

signature_request.done (YouSign) et envelope-completed (DocuSign) annoncent que les PDF finaux sont prêts. Une reprise des emails de fin ne bloque ni cette notification ni le téléchargement API. Le worker prend en charge les notifications enregistrées et leurs reprises chaque minute ; la réception dépend aussi de sa charge et de la disponibilité de votre serveur. Répondez avec un statut HTTP 2xx après prise en charge. Une notification peut être rediffusée après une réponse perdue : dédupliquez par event_id pour YouSign, ou par demande et événement pour DocuSign.