> For the complete documentation index, see [llms.txt](https://docs.sign.enadocapp.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.sign.enadocapp.com/evia-sign-api/v2/webhook-management/retrieve-completed-documents-from-a-webhook.md).

# Retrieve Completed Documents from a Webhook

## Overview

When Evia Sign sends a signing\_completed or request.completed webhook, the completed documents are ready for retrieval. Before downloading, validate the webhook and exchange your API key for a short-lived access token.

Follow the steps below to retrieve the completed documents securely:

1. Receive the webhook and read requestId, deliveryId, and event ID.
2. Validate X-Webhook-Signature when HMAC security is enabled.
3. Use deliveryId as an idempotency key to prevent repeat downloads.
4. Exchange the API key for an access token.
5. List and download the required completed documents.

## Webhook response

\
The webhook payload includes the identifiers needed to correlate the event and retrieve its completed documents. Preserve the raw body before HMAC verification.

```
{
  "deliveryId": "delivery-123",
  "eventId": "signing_completed",
  "tenantId": "tenant-123",
  "requestId": "request-123",
  "requestTitle": "document-123.pdf",
  "timestamp": "2026-09-04T10:00:00Z",
  "schemaVersion": "1.0"
}
```

<table><thead><tr><th width="172">Field</th><th>Use</th></tr></thead><tbody><tr><td>deliveryId</td><td>Unique delivery identifier. Store it to make webhook handling idempotent.</td></tr><tr><td>eventId</td><td>Event type, for example signing_completed.</td></tr><tr><td>tenantId</td><td>Tenant ID of the request</td></tr><tr><td>requestId</td><td>Use this ID to list the completed documents.</td></tr><tr><td>requestTitle</td><td>Human-readable request title. Use it for display only.</td></tr><tr><td>timestamp</td><td>Event time in UTC.</td></tr><tr><td>schemaVersion</td><td>Payload schema version for compatible processing.</td></tr></tbody></table>

{% hint style="info" %} <mark style="color:$primary;">**IMPORTANT**</mark> For HMAC-enabled webhooks, calculate HMAC-SHA-256 using the raw request body and compare it with X-Webhook-Signature. Do this before exchanging a token or downloading files.
{% endhint %}

### &#x20;1. Exchange API key for access token

Before calling a document endpoint, exchange the integration API key for a scoped Bearer token. The API key identifies the integration; do not use it directly for document download calls.

Send the following request:

```
POST /api/v2/oauth/exchange
Content-Type: application/json
X-Api-Key: <raw_api_key>

{}
```

After a successful exchange, Evia Sign returns the following values:

```
{
"access_token": "",
"token_type": "Bearer",
"expires_in": 1800
}
```

{% hint style="info" %} <mark style="color:$primary;">**TOKEN LIFETIME**</mark> The access token is valid for 1,800 seconds (30 minutes). Keep it only until expiry, then exchange the API key again when needed.
{% endhint %}

### 2. List completed documents

Use the requestId from the webhook to list the available completed documents and their secure download URLs. The response includes signed documents and, when available, the audit trail.

Send the following request:

```
GET https://evia.enadocapp.com/_apis/sign/api/v2/requests/{requestId}/documents
Authorization: Bearer <access_token>
Accept: application/json
```

Evia Sign returns an array like the following:

```
[
  {
    "documentName": "Construction_Contract.pdf",
    "downloadUrl": "https://evia.enadocapp.com/_apis/sign/api/v2/documents/{opaque-document-token}/download"
  },
  {
    "documentName": "audit_trail.pdf",
    "downloadUrl": "https://evia.enadocapp.com/_apis/sign/api/v2/documents/{opaque-audit-trail-token}/download"
  }
]
```

### 3. Download a document from the response

Call the exact downloadUrl returned for the document you need. The opaque document token is already part of this URL. Do not construct it from documentId or the file name.

Send the following request:

```
GET {downloadUrl}
Authorization: Bearer <access_token>
```

{% hint style="info" %} <mark style="color:$primary;">**NO REQUEST BODY**</mark> The downloadUrl endpoint uses GET. Do not send the webhook JSON payload in the request body. Content-Type is not required unless your HTTP client adds it automatically.
{% endhint %}

#### Download the audit trail

Locate the item where documentName is audit\_trail.pdf, then use its downloadUrl. Download and save it in the same way as any other completed document.

## End-to-end example

1. **Receive the webhook** - Read requestId and deliveryId. Validate the HMAC signature when webhook security is enabled.
2. **Prevent duplicate processing** - Store deliveryId and stop processing if the same delivery has already succeeded.
3. **Exchange the API key** - Call /api/v2/oauth/exchange with X-Api-Key and read access\_token.
4. **Retrieve the documents** - Call the list-documents endpoint, then call each returned downloadUrl for the files you need.
5. **Save the files** - Save the files in a request-specific location. Mark deliveryId as processed only after the download succeeds.

## Failure handling

<table><thead><tr><th width="211">Condition</th><th>Recommended action</th></tr></thead><tbody><tr><td>Invalid webhook signature</td><td>Reject the delivery; do not call the token or document endpoints.</td></tr><tr><td>Duplicate deliveryId</td><td>Return success without downloading the files again.</td></tr><tr><td>401 or expired token</td><td>Exchange the API key again and retry once.</td></tr><tr><td>Request not completed</td><td>Do not download. Wait for the completed event or retry according to your delivery policy.</td></tr><tr><td>Download failure</td><td>Log requestId and deliveryId; retry safely without creating duplicate records.</td></tr></tbody></table>
