# Envelopes

_An envelope is one PDF for one or more recipients. The fundamental unit of work; everything else composes onto it._

_Last updated: 2026-05-07_

---

# Envelopes

An **envelope** is one PDF sent to one or more recipients for signature. It's the fundamental unit of work: when callers think about "send a contract" or "collect a signature on this document," they're thinking about an envelope.

## The pieces

### Envelope

The container. Carries:

- **A PDF.** Either uploaded directly (multipart form on `POST /v1/envelopes`) or instantiated from a [template](#templates).
- **A title.** Free-text label for the customer side; appears in dashboards and notification emails.
- **A status.** Tracks the envelope's lifecycle.
- **A storage expiry.** Optional; the underlying signing engine retains the completed PDF for the configured number of days, after which it's purged.

### Recipient

A person or role that interacts with the envelope. One envelope can have up to ten recipients in V1. Each recipient has:

- **Email.** Where the signing-link notification is sent.
- **Name.** Displayed in the signing UI.
- **Role.** One of:
  - `SIGNER` — adds a binding signature.
  - `APPROVER` — must approve before signers can sign (sequenced workflows).
  - `VIEWER` — can read the envelope but doesn't sign.
  - `CC` — receives a copy of the completed envelope but doesn't interact.
  - `ASSISTANT` — fills fields on behalf of a signer (delegated data entry, no signature authority).

### Field

A placeable element on the PDF. Coordinate-based (percentage of page) OR PDF-placeholder-marker-based (`[component]}` literals embedded in the source PDF).

Field types:

`SIGNATURE`, `INITIALS`, `NAME`, `EMAIL`, `DATE`, `TEXT`, `NUMBER`, `CHECKBOX`, `RADIO`, `DROPDOWN`.

Each field is bound to one recipient via their email; only that recipient can fill the field.

### Template

A saved envelope definition. PDFs + field placements + recipient roles, parameterized so a new envelope can be instantiated from the template with just-the-recipients-changed.

Templates are esignature-specific; they don't surface on the lodestone path (which is single-shot by design). Created via `POST /v1/templates`; instantiated via `POST /v1/templates/id/from-template`.

## Lifecycle

```
DRAFT → PENDING → SENT → PARTIALLY_SIGNED → COMPLETED
```

With three alternative terminal states:

```
SENT → REJECTED   (a signer rejected; flow halts; refund-on-terminal triggers)
SENT → EXPIRED    (the signing window closed without all signers; refund-on-terminal triggers)
SENT → CANCELLED  (the customer or operator cancelled; refund-on-terminal triggers)
```

The four terminal states (`COMPLETED`, `REJECTED`, `EXPIRED`, `CANCELLED`) are the only states from which an envelope cannot transition.

`DRAFT` is the initial status when `POST /v1/envelopes` is called without a `fields` array. Mutations on the draft (`POST /:id/fields`, `DELETE /:id/fields/fid`) only work while the envelope is `DRAFT`. Once `POST /:id/send` distributes the envelope, no more field changes are allowed.

For the simple workflow — one PDF, fields known up front — call `POST /v1/envelopes` with the fields array included in the payload, and the envelope skips `DRAFT` and goes straight to `PENDING`/`SENT`.

## Sending and signing

### Distribution

When an envelope transitions to `SENT`, each recipient gets a signing-link email from the underlying signing engine. The link carries a token bound to that recipient; opening it loads the signing UI with their fields pre-targeted.

### Signing

The signing UI is hosted by the underlying signing engine (Documenso) at `sign.verafirma.com`. Signers fill their fields, click sign, and the engine generates a signed-PDF artifact bound to the envelope. When all `SIGNER` recipients have signed, the envelope transitions to `COMPLETED`.

The signing UI reflects the operator's brand — the API consumer doesn't supply a signing UI; the wrapped engine handles it.

### Reminders

Recipients who haven't signed get periodic reminder emails (cadence configured at the engine). The customer can also chase manually:

```sh
curl -X POST https://api.verafirma.com/v1/envelopes/id/resend \
  -H "Authorization: Bearer vf_live_..."
```

This re-sends the signing link to NOT_SIGNED recipients without changing the envelope's state.

### Cancellation

A SENT envelope can be cancelled before all signatures land:

```sh
curl -X DELETE https://api.verafirma.com/v1/envelopes/id \
  -H "Authorization: Bearer vf_live_..."
```

Cancellation transitions the envelope to `CANCELLED` and triggers the refund-on-terminal flow (the original charge is refunded up to the per-envelope cap).

## Reading state

### Cached vs. live

Two read endpoints with different freshness:

- `GET /v1/envelopes/id` — returns the wrapper's cached state. Fast (sub-100ms typically); reflects whatever the wrapper last persisted from a webhook event or read.
- `GET /v1/envelopes/id/status` — fetches authoritative state from the underlying signing engine, reconciles the cache if it had drifted, and returns the live shape.

Use `/status` when accuracy matters (e.g. before completing a downstream action that depends on signature completion). Use the cached read for high-volume polling where eventual consistency is fine.

### Listing

`GET /v1/envelopes?limit=&offset=&status=` returns paginated envelopes for the authenticated customer. The `status` filter is exact-match against the V1 status enum.

### Downloading

`GET /v1/envelopes/id/download?version=signed` streams `application/pdf`. Only available when the envelope is `COMPLETED`. The `version` query is `signed` (default — the signed artifact) or `original` (the source PDF before signing).

## Limits

V1 caps each envelope at:

- **≤10 signers** AND **≤10 documents.** Anything larger returns `400 OUT_OF_SCOPE_V1`.

These limits are tunable post-deploy (per the operator's configuration surface) but the V1 defaults won't move without explicit operator action. If you have a use case that needs >10 of either, contact the operator.

## Pricing

$0.10 per envelope, charged at creation. Refunded on terminal failure (`REJECTED`, `EXPIRED`, `CANCELLED`) up to a configurable per-envelope cap. See [`/pricing`](/pricing) for the per-mode breakdown.
