> ## Documentation Index
> Fetch the complete documentation index at: https://docs.didit.me/llms.txt
> Use this file to discover all available pages before exploring further.

# Electronic Signature Report

> Read signatures[] in the session decision and webhooks, download the signed PDFs and the evidence PDF, and validate a signature again.

Every [Electronic Signature](/core-technology/electronic-signature/overview) step produces one result per signer. You find it as an item of `signatures[]` in:

* [`GET /v3/session/{sessionId}/decision/`](/sessions-api/retrieve-session), for User Verification (KYC) and Business Verification (KYB) sessions.
* The `decision` of V3 [session webhooks](/integration/webhooks), sent when the session is `Approved`, `Declined`, `In Review` or `Abandoned`.
* The session's **Signature** tab in the console, and the signature section of the [PDF report](/sessions-api/generate-pdf).

`signatures` is only in the decision when the workflow has an Electronic Signature step. It's an empty array until a signer reaches the step. A KYC step has one item; a KYB step has one item per signer.

## Example

```json theme={null}
{
  "signatures": [
    {
      "id": "0e6c2a8e-6c2f-4b8e-9a51-3f2f6a7d9b10",
      "node_id": "feature_signature",
      "status": "signed",
      "verdict": "Approved",
      "level": "aes",
      "format": "pades",
      "profile": "PAdES-B-LT",
      "signer": {
        "name": "Jane Doe",
        "capacity": "self",
        "company": null,
        "role": null,
        "roles": [],
        "identity_session_id": "11111111-2222-3333-4444-555555555555"
      },
      "identity_used": {
        "session_id": "11111111-2222-3333-4444-555555555555",
        "kyc_id": "6f1e8f6c-1d2b-4c3a-9e8f-7a6b5c4d3e2f",
        "verified": true,
        "expected_name": "Jane Doe"
      },
      "certificate": {
        "issuer": "<certificate issuer>",
        "issued_to": "<certificate subject>",
        "serial": "5A3F9C21",
        "valid_from": "2026-01-01T00:00:00+00:00",
        "valid_until": "2028-01-01T00:00:00+00:00"
      },
      "confirmation": {
        "channel": "email",
        "destination": "j***@example.com",
        "confirmed_at": "2026-11-03T10:42:18.512Z",
        "attempts": 1
      },
      "timestamp": {
        "time": "2026-11-03T10:42:21+00:00",
        "qualified": false,
        "valid": true
      },
      "documents": [
        {
          "id": "9b0a7f44-2c1d-4e5f-8a9b-0c1d2e3f4a5b",
          "uuid": "9b0a7f44-2c1d-4e5f-8a9b-0c1d2e3f4a5b",
          "title": "Account agreement",
          "file_name": "agreement.pdf",
          "pages": 4,
          "size_bytes": 182344,
          "sha256_original": "3b8e5f0c2a9d4e7f1b6c0a5d9e8f7a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f",
          "sha256_signed": "a1f2e3d4c5b6a7980f1e2d3c4b5a69788f7e6d5c4b3a29180f1e2d3c4b5a6978",
          "status": "signed",
          "opened_at": "2026-11-03T10:40:02.118Z",
          "read_at": "2026-11-03T10:41:10.044Z",
          "read_to_end": true,
          "consented_at": "2026-11-03T10:41:12.730Z",
          "consent": true,
          "signed_file": "/v3/session/11111111-2222-3333-4444-555555555555/signatures/feature_signature/documents/9b0a7f44-2c1d-4e5f-8a9b-0c1d2e3f4a5b/file/",
          "mode": "fields",
          "source_format": "pdf",
          "conversion": null,
          "fields": [
            {
              "key": "full_name",
              "type": "full_name",
              "role": "verified_person",
              "label": "Full name",
              "page": 1,
              "x": 0.34,
              "y": 0.2326,
              "width": 0.57,
              "height": 0.0325,
              "required": true,
              "value": "Jane Doe",
              "display_value": "Jane Doe",
              "value_source": "identity",
              "filled_at": "2026-11-03T10:40:02.118Z",
              "value_unavailable_reason": null
            },
            {
              "key": "occupation",
              "type": "text",
              "role": "verified_person",
              "label": "Occupation",
              "page": 1,
              "x": 0.34,
              "y": 0.4618,
              "width": 0.57,
              "height": 0.0325,
              "required": true,
              "value": "Architect",
              "display_value": "Architect",
              "value_source": "signer",
              "filled_at": "2026-11-03T10:40:41.502Z",
              "value_unavailable_reason": null
            },
            {
              "key": "signature",
              "type": "signature",
              "role": "verified_person",
              "label": "Signature",
              "page": 4,
              "x": 0.09,
              "y": 0.5303,
              "width": 0.36,
              "height": 0.0849,
              "required": true,
              "value": true,
              "display_value": "Signed",
              "value_source": "signer",
              "filled_at": "2026-11-03T10:41:05.200Z",
              "image_url": "/v3/session/11111111-2222-3333-4444-555555555555/signatures/feature_signature/fields/c4d5e6f7-0a1b-4c2d-8e3f-4a5b6c7d8e9f/image/",
              "value_unavailable_reason": null
            }
          ]
        }
      ],
      "adopted_signature": {
        "method": "drawn",
        "font": null,
        "adopted_at": "2026-11-03T10:41:02.871Z"
      },
      "electronic_signature_consent_at": "2026-11-03T10:41:40.016Z",
      "evidence_file": "/v3/session/11111111-2222-3333-4444-555555555555/signatures/feature_signature/evidence/?signature_id=0e6c2a8e-6c2f-4b8e-9a51-3f2f6a7d9b10",
      "warnings": [],
      "validation": {
        "valid": true,
        "checked_at": "2026-11-03T10:42:24.903Z",
        "documents": [
          {
            "id": "9b0a7f44-2c1d-4e5f-8a9b-0c1d2e3f4a5b",
            "checked_at": "2026-11-03T10:42:24.903Z",
            "valid": true,
            "integrity": true,
            "trusted": true,
            "revoked": false,
            "trusted_list": { "status": "not_applicable", "reason": "aes_not_qualified" },
            "certificate": {
              "issuer": "<certificate issuer>",
              "issued_to": "<certificate subject>",
              "serial": "5A3F9C21",
              "valid_from": "2026-01-01T00:00:00+00:00",
              "valid_until": "2028-01-01T00:00:00+00:00"
            },
            "timestamp": { "time": "2026-11-03T10:42:21+00:00", "qualified": false, "valid": true }
          }
        ]
      },
      "declined_at": null,
      "declined_action": "REVIEW",
      "signed_at": "2026-11-03T10:42:24.903Z",
      "expires_at": "2026-11-10T10:30:00.000Z",
      "email_sent_at": "2026-11-03T10:42:30.011Z",
      "email_unavailable_reason": null,
      "ip_address": "203.0.113.10",
      "place": null,
      "place_unavailable_reason": "not_collected"
    }
  ]
}
```

## The signature object

| Field | Type | Description |
| - | - | - |
| `id` | string (UUID) | The signer's signature. Pass it as `signature_id` to download their evidence or validate their signature. |
| `node_id` | string | The workflow step that produced it. |
| `status` | string | Where the signer is in the step: `intro`, `review`, `code`, `signing`, `signed` or `declined`. Only `signed` means the documents are signed. |
| `verdict` | string | The step's outcome: `Not Finished`, `Approved`, `In Review` or `Declined`. A declined or failed signature takes the verdict of its [rule](/core-technology/electronic-signature/warnings-electronic-signature), and custom status rules can change it. |
| `level` | string | `aes`. `qes` is coming soon. |
| `format` | string | `pades`. |
| `profile` | string \| null | `PAdES-B-LT` once signed, otherwise `null`. |
| `signer` | object | Who signed. See [Signer](#signer). |
| `identity_used` | object | The verified identity the signature relies on. See [Signer](#signer). |
| `certificate` | object \| null | The certificate the documents were signed with: `issuer`, `issued_to`, `serial`, `valid_from` and `valid_until`. `null` until signed. |
| `confirmation` | object | The one-time code: `channel` (`email` or `sms`), `destination` (the masked contact it went to), `confirmed_at`, and `attempts` (codes entered, the right one included). |
| `timestamp` | object \| null | The trusted timestamp in the signature: `time`, `qualified` (always `false` for AES) and `valid`. `null` until signed. |
| `documents` | array | One item per document. See [Documents](#documents). |
| `adopted_signature` | object \| null | The signature and initials the signer adopted for signature and initials fields: `method` (`typed` or `drawn`), `font` (the handwriting style of a typed signature, or `null` when drawn) and `adopted_at`. `null` until the signer adopts one. |
| `electronic_signature_consent_at` | string \| null | When the signer agreed, on the review screen, to sign the documents electronically. Set when any document has fields. |
| `evidence_file` | string \| null | Path to this signer's [evidence PDF](#the-evidence-pdf), once signed. |
| `warnings` | array | `{ "code", "node_id" }` items for each [warning](/core-technology/electronic-signature/warnings-electronic-signature) raised. |
| `validation` | object \| null | The last cryptographic check of the signed documents. See [Validate a signature again](#validate-a-signature-again). |
| `declined_at` | string \| null | When the signer declined. |
| `declined_action` | string | The step's `signature_declined_action`: what a decline does to the verdict. |
| `signed_at` | string \| null | When the documents were signed. |
| `expires_at` | string | When the signing link stops working. |
| `email_sent_at` | string \| null | When Didit emailed the signer a signed copy. |
| `email_unavailable_reason` | string \| null | Why no copy was emailed, when you asked for one. |
| `ip_address` | string \| null | The signer's IP address when they asked for their code. |
| `place` | string \| null | Not collected. Always `null`, with `place_unavailable_reason: "not_collected"`. |

A `null` certificate, timestamp or `signed_file` means there is no signature yet. Never treat a signer as having signed until `status` is `signed`.

### Signer

| Field | Description |
| - | - |
| `signer.name` | The signer's verified name, from their approved ID verification. |
| `signer.capacity` | `self` when a person signs for themselves (KYC), `company` when a key person signs for a company (KYB). |
| `signer.company` | The company's name, for KYB. |
| `signer.role` | The key person's designation, as declared, for KYB. |
| `signer.roles` | The key person's structured roles, such as `representative` or `authorized_signatory`, that made them a signer. These are the roles declared for the company, not a registry confirmation. |
| `signer.identity_session_id` | The KYC session that verified the signer. For KYB, the key person's own KYC session. |
| `identity_used.session_id` | Same as `signer.identity_session_id`. |
| `identity_used.kyc_id` | The ID verification the name came from. |
| `identity_used.verified` | `true` when that ID verification was approved. |
| `identity_used.expected_name` | The name the signer had to match. For KYB, the name declared for the key person. |

### Documents

| Field | Description |
| - | - |
| `id`, `uuid` | The document. Use it to download the signed file. |
| `title`, `file_name` | As uploaded or sent. |
| `pages`, `size_bytes` | Of the document the signer signed. For Word, of the converted PDF. |
| `sha256_original` | SHA-256 of the document as the signer was shown it. |
| `sha256_signed` | SHA-256 of the signed PDF, once signed. |
| `status` | `signed`; `declined`; `not_signed` (opened, not signed); or `not_reached` (never opened). |
| `opened_at` | When the signer first opened it. |
| `read_at`, `read_to_end` | When the signer reached the end of a document without fields, when you require reading to the end. A document with fields doesn't need it. |
| `consented_at`, `consent` | When the signer agreed to a document without fields, when you require consent per document, or finished the fields of a document with fields. |
| `signed_file` | Path to the signed PDF, once signed. |
| `mode` | `fields` for a document with fields, `read_and_agree` for a document without. |
| `source_format` | `pdf`, or `docx` for a Word document Didit converted. |
| `conversion` | `null` for a PDF. For a Word document, `{ "from": "docx", "file_name", "sha256", "size_bytes", "converter" }`: your original file, its SHA-256 and size, and the version of the converter. |
| `fields` | The [fields](#fields) on the document, with their values. Empty for a document without fields. |

### Fields

Each item of `documents[].fields[]` is one field of the document, with its value on this signer's copy:

| Field | Description |
| - | - |
| `key` | The field's [key](/core-technology/electronic-signature/overview#fields-on-the-document), the same one you use in `sign.field_values`. |
| `type`, `role`, `label`, `required` | As placed on the document. |
| `page`, `x`, `y`, `width`, `height` | Where the field sits, as fractions of the page as displayed. |
| `value` | A string for `text`, `email`, `full_name`, `date_signed` and `data` fields, a boolean for a checkbox, and `true` for an applied signature or initials. `null` when the field is empty. |
| `display_value` | The value as it's stamped on the page: dates in the field's `date_format`, `Yes` or `No` for a checkbox, and `Signed` for a signature or initials. |
| `value_source` | Where the value came from: `signer` (typed, ticked or applied by the signer), `identity` (the verified ID), `contact` (the verified email or phone), `company` (the verified company), `session` (the session's `vendor_data`), `metadata` (the session's `metadata`), `api` (your `sign.field_values`) or `signing_time` (the date signed). |
| `filled_at` | When the value was set. |
| `image_url` | For a signature or initials, the path of the applied image, a PNG. See [Download a signature image](/sessions-api/electronic-signature/download-field-image). |
| `value_unavailable_reason` | `source_empty` when a pre-filled field had no value in the session and `signature_field_data_missing_action` let the signer sign anyway. Otherwise `null`. |

## Download the signed documents

Use the paths in `signed_file` and `evidence_file` with your API key. Each route answers with the PDF itself.

```bash theme={null}
# Signed PDF of one document
curl -L 'https://verification.didit.me/v3/session/{session_id}/signatures/{node_id}/documents/{document_id}/file/' \
  -H 'x-api-key: YOUR_API_KEY' \
  -o agreement-signed.pdf

# Evidence PDF of one signer
curl -L 'https://verification.didit.me/v3/session/{session_id}/signatures/{node_id}/evidence/?signature_id={signature_id}' \
  -H 'x-api-key: YOUR_API_KEY' \
  -o signature-evidence.pdf
```

| Route | Reference |
| - | - |
| `GET .../documents/{document_id}/file/` | [Download a signed document](/sessions-api/electronic-signature/download-signed-document) |
| `GET .../evidence/` | [Download the signature evidence](/sessions-api/electronic-signature/download-evidence) |
| `GET .../fields/{field_id}/image/` | [Download a signature image](/sessions-api/electronic-signature/download-field-image) |
| `POST .../validate/` | [Validate signatures](/sessions-api/electronic-signature/validate-signatures) |

Before answering, Didit checks the stored file against its recorded SHA-256. If they differ, the signed PDF and evidence routes return `409` and the image route returns `400`, each with `signature_document_changed`. Always pass `signature_id` to the evidence route when a KYB step has several signers.

## The signed PDF

The signed PDF holds, in order:

1. The pages of the document the signer was shown, with every field value stamped where you placed it.
2. The evidence page, unless you turned off `signature_evidence_page`.
3. The PAdES signature, with the trusted timestamp and the revocation data needed to validate it in the future.

The signature covers every byte before it, field values and evidence page included. Changing anything in the file afterwards invalidates it, and any PAdES-capable validator shows that. The signature's details name the signer and refer to their verified identity session and code confirmation.

Field values become part of the page content, not form fields, so they can't be edited later and every PDF viewer shows them. A ticked checkbox shows a tick, and an unticked one is left as the document drew it. A signature box taller than 24 points also gets a small caption under the signature: `Signed with Didit ·` followed by the first 8 characters of the signature's `id`.

Didit adds the field values, the evidence page and the signature after the bytes of the document the signer was shown. That document is an exact prefix of the signed file, so `sha256_original` can still be checked against the signed PDF.

## The evidence PDF

The evidence PDF records, for one signer:

* The level and format.
* The signer's name, their signing capacity and, for KYB, the company.
* The verified identity session.
* The confirmation: channel, masked destination and time.
* The signer's IP address.
* Each document: title, number of pages and SHA-256 of the original. For a Word document, the Word file's name and SHA-256, the converter version and the SHA-256 of the PDF.
* The adopted signature: typed (with its handwriting style) or drawn, when it was adopted, and the signature and initials images.
* Each field, per document: its label, page and type, its value (the image for a signature or initials), where the value came from (for example **Typed by the signer**, **Verified ID** or **Your API**), when it was filled (UTC) and, for a value the signer typed, their IP address at that time.
* The final consent: the text the signer agreed to on the review screen, and when.
* The certificate (issued to, issuer, serial and validity), the timestamp and the SHA-256 of every signed file.

The page appended to each signed PDF has the same content without the certificate section, because it's added before the signature is applied.

## Validate a signature again

`POST /v3/session/{session_id}/signatures/{node_id}/validate/` re-reads every signed PDF of the step, checks its SHA-256 and validates the PAdES signature, its certificate, the revocation data and the timestamp. It saves the result in `validation` and returns the updated `signatures[]`. Send `signature_id` to check one signer. It needs `write:sessions`, and in the console it's the **Validate again** button. A stored signed PDF that no longer matches its `sha256_signed` returns `400` with `signature_document_changed`.

Until the documents are signed, `validation` is `null`. If Didit can't confirm the outcome of signing, `validation` is `{ "valid": null, "reason": "signature_provider_outcome_unknown", "checked_at" }` and `status` stays `signing` until it's resolved: treat it as not signed.

| Field of `validation.documents[]` | Description |
| - | - |
| `valid` | `true` when the signature and the timestamp are both valid and trusted. |
| `integrity` | `true` when the document is unchanged since signing. |
| `trusted` | `true` when the signing certificate chains to a trusted root. |
| `revoked` | `true` when the signing certificate was revoked. |
| `trusted_list` | `{ "status": "not_applicable", "reason": "aes_not_qualified" }` for AES. The EU Trusted List check applies to qualified signatures. |
| `certificate`, `timestamp` | As found in the file. |

## In the PDF report

The [PDF report](/sessions-api/generate-pdf) prints a signature section with the signer, the confirmation, the certificate, the timestamp and the documents with their hashes. When the documents have fields, an **Electronic signature · fields** page follows, with one table per document: every field's value, the signature and initials images, the times and the sources. The signature section comes after Bank verification in a KYC report and after Documents in a KYB report. Pass `pages=signature` to print only that section.

## Related

* [Electronic Signature overview](/core-technology/electronic-signature/overview)
* [Electronic Signature warnings](/core-technology/electronic-signature/warnings-electronic-signature)
* [Data models: electronic signature](/reference/data-models#electronic-signature)
* [Webhooks](/integration/webhooks)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.