---
title: "Store final stamped PDF hash and signer's final signature"
method: POST
path: "/api/envelopes/{envelope_id}/finalize"
---

# Store final stamped PDF hash and signer's final signature

`POST /api/envelopes/{envelope_id}/finalize`

## Request

- Base URL: `https://free-sign.com`
- URL: `https://free-sign.com/api/envelopes/{envelope_id}/finalize`
- Auth: none declared. Required headers: `x-fsig-session-signature`, `x-fsig-session-nonce`, `x-fsig-session-timestamp`, `x-fsig-session-action`

Browser stamps the PDF locally, hashes the stamped PDF, then signs a canonical final payload with the SAME ECDSA key used for /sign. The server verifies that signature with the public key already on file. Idempotent: once final_pdf_sha256 is set, the endpoint returns 409 already_finalized. Requires the four session-binding headers (see x-fsig-session-* component parameters).

## Path parameters

- `envelope_id` string, required

## Headers

- `x-fsig-session-signature` string, required
- `x-fsig-session-nonce` string, required
- `x-fsig-session-timestamp` string, date-time, required
- `x-fsig-session-action` 'otp.request' | 'otp.verify' | 'sign' | 'seal' | 'platform-seal' | 'finalize' | 'webauthn.register' | 'webauthn.authenticate', required

## Request body

- object
  - `signer_id` string, required
  - `final_pdf_sha256` string, required
  - `final_payload` object, required: Final payload v2 — canonical-JSON object signed by the browser with the same ECDSA P-256 key as /sign. Strict key set: the server rejects unknown keys with 400 and requires app === "free-sign.com". audit_chain_head_hash is the event_hash of the latest audit event at finalize time; the server re-derives the current chain head and rejects on mismatch, freezing the audit chain in signed evidence (security audit G-01).
    - `app` 'free-sign.com', required
    - `envelope_id` string, required
    - `document_sha256` string, required
    - `final_pdf_sha256` string, required
    - `payload_hash` string, required
    - `audit_chain_head_hash` string, required
    - `finalized_at` string, date-time, required
  - `final_signature_base64url` string, required

## Response `200`

Final PDF hash and signature stored.

## Other responses

- `409`: Envelope already finalized.

---

[API](https://skmtc.dev/free-sign/apis/freesign-free-e-signature-api.md) · [All operations](https://skmtc.dev/free-sign/apis/freesign-free-e-signature-api/llms.txt) · [OpenAPI document](https://skmtc.dev/free-sign/apis/freesign-free-e-signature-api/revisions/5d8e9854ab85?raw)
