---
title: "Get an envelope"
method: GET
path: "/envelopes/{envelopeId}"
tags: ["Envelopes"]
---

# Get an envelope

`GET /envelopes/{envelopeId}`

## Request

- Base URL: `https://inkseal.net/api/v1`
- URL: `https://inkseal.net/api/v1/envelopes/{envelopeId}`
- Auth: HTTP bearer

Full envelope detail, including every signer with its routing position, its lifecycle timestamps, and the fields assigned to it with their fill state.

This is the poll target after a send: watch `status` until it leaves `sending`. `completedPdfHash` is the SHA-256 of the executed PDF and is null until the envelope completes.

An envelope in another workspace answers 404, the same as an unknown id.

## Response `200`

The envelope, its document, its signers with fields, and computed send readiness.

- object
  - `data` EnvelopeDetail, required: One envelope in full, as `GET /envelopes/{envelopeId}` publishes it.
    - `id` string, required
    - `status` 'draft' | 'sending' | 'pending' | 'completing' | 'completed' | 'declined' | 'voided' | 'expired', required: Where the envelope is in its lifecycle. `sending` and `completing` are transient; `completed`, `declined`, `voided`, and `expired` are terminal.
    - `subject` string, nullable, required
    - `message` string, nullable, required: Body text carried in the invitation email.
    - `signingOrder` 'parallel' | 'sequential', required
    - `emailVerification` boolean, required: Whether a signer must pass an emailed one-time code before signing.
    - `template` EnvelopeTemplateProvenance, nullable, required
      - `id` string, nullable, required: Null after the source template is deleted.
      - `version` integer, required
    - `document` EnvelopeDocumentSummary, required: The document the envelope was built from, as the envelope routes publish it: the public id and the original upload filename, nothing else.
      - `id` string, required: Public document id.
      - `filename` string, required: The filename as uploaded.
    - `signers` SignerDetail[], required
      - `id` string, required
      - `name` string, required
      - `email` string, email, required
      - `role` 'signer' | 'approver' | 'reviewer', required: What the recipient is asked to do. `signer` executes the document and must be assigned at least one field. `approver` approves or declines and may hold fields. `reviewer` acknowledges having read it and may hold none. Defaults to `signer`.
      - `status` 'pending' | 'sent' | 'viewed' | 'signed' | 'approved' | 'acknowledged' | 'declined', required: Where one recipient is. `pending` means not yet invited, which on a sequential envelope is normal for everyone behind the current turn. `signed`, `approved` and `acknowledged` are the three positive terminal states, one per role: a signer signs, an approver approves, a reviewer acknowledges.
      - `order` integer, required: Normalized 1-based routing position. On a parallel envelope it is still assigned but does not gate anything.
      - `viewedAt` string, date-time, nullable, required
      - `signedAt` string, date-time, nullable, required
      - `declinedAt` string, date-time, nullable, required
      - `declineReason` string, nullable, required: What the signer typed when declining, when they gave a reason.
      - `fields` FieldDetail[], required
        - `id` string, required
        - `type` 'signature' | 'initials' | 'text' | 'date' | 'checkbox' | 'number' | 'email' | 'select' | 'radio' | 'textarea', required: How the field is filled and rendered. Values are stored as strings; signature and initials use images.
        - `required` boolean, required: Whether the signer must fill this field to complete.
        - `pageIndex` integer, required
        - `filled` boolean, required: True once the field carries a value.
        - `filledAt` string, date-time, nullable, required
    - `readiness` EnvelopeReadiness, required: Computed send readiness. It is never persisted and may change after a draft edit.
      - `canSend` boolean, required: True when no readiness issue blocks sending. Credit availability is separate.
      - `issues` ReadinessIssue[], required
        - union
          - MissingSenderValueIssue
            - `code` 'missing_sender_value', required
            - `fieldId` string, required
            - `name` string, nullable, required
            - `label` string, nullable, required
          - InvalidSenderValueIssue
            - `code` 'invalid_sender_value', required
            - `fieldId` string, required
            - `name` string, nullable, required
            - `detail` string, required: Safe, human-readable validation detail.
          - UnassignedFieldIssue: Reserved for forward compatibility. Current persisted envelopes do not produce this issue.
            - `code` 'unassigned_field', required
            - `fieldId` string, required
          - NoSignerFieldsIssue
            - `code` 'no_signer_fields', required
    - `values` NamedFieldValues, required: Named field values keyed by the stable field name. Unnamed fields are omitted. Values keep their stored string representation; an unfilled field is null.
    - `completedPdfHash` string, nullable, required: SHA-256 of the executed PDF. Null until the envelope completes.
    - `sentAt` string, date-time, nullable, required
    - `completedAt` string, date-time, nullable, required
    - `expiresAt` string, date-time, nullable, required
    - `createdAt` string, date-time, required
    - `pendingApproval` object, nullable, required: The approval a person still has to give before this draft is sent, on a workspace whose `agentSendApproval` setting is `required`. Null on every other envelope. This is what an agent polls after `sendEnvelope` answers `pending_approval`: the block clears and the status leaves `draft` once a person approves.
      - `id` string, required: The approval's public id, as returned by `sendEnvelope`.
      - `requestedBy` string, nullable, required: The agent identity of the credential that asked.
      - `requestedAt` string, date-time, required
      - `expiresAt` string, date-time, required: When the request lapses if nobody answers it.
    - `activeStep` integer, nullable, required: The step whose signers may act now, or null once every signer has signed.
    - `steps` EnvelopeSigningStep[], required: The routing chain, however the envelope was created.
      - `step` integer, required
      - `status` 'completed' | 'active' | 'pending': Where this step sits relative to the step the envelope is on.
      - `signers` string[], required: Public ids of the signers in this step.
    - `creditCost` integer, required: Credits sending this envelope costs: one for the envelope, one for each signer who is not the sender, and one more when `emailVerification` is on. An unmetered workspace is quoted the same price and charged nothing.
    - `creditLines` CreditLine[], required: The same total broken into its lines.
      - `kind` 'envelope' | 'signer' | 'otp', required
      - `quantity` integer, required: How many units this line charges for.
      - `unitCredits` integer, required: Credits per unit.
      - `credits` integer, required: `quantity` times `unitCredits`.

## Other responses

- `401`: The credential is missing, malformed, unknown, expired, revoked, or past its rotation grace window. Code: `unauthorized`. Every authentication failure is deliberately indistinguishable.
- `403`: The credential is valid but may not do this. Codes: `insufficient_scope` (the route's scopes are not all held; `details` names `requiredScopes` and `missingScopes`), `forbidden` (the capability check on the resolved resource failed), `scope_escalation` (a grant wider than the caller's own was requested).
- `404`: The resource does not exist, was deleted, or belongs to another workspace. Code: `not_found`. The three cases are answered identically on purpose, so a 404 never confirms that an identifier exists elsewhere.
- `429`: A limit was reached. Codes: `rate_limited` (the credential's per-bucket HTTP limit, or the per-workspace detection throttle), `workspace_limit_exceeded` (a workspace content or send limit; `details.limit` names it), `daily_budget_exceeded` (the workspace's daily detection budget). The four rate-limit headers are sent on this response and on no successful one, so a client cannot read its remaining budget without being refused. Retrying after `Retry-After` is always safe: a rate-limit refusal happens before the handler runs.
- `503`: A dependency the request needs is unreachable and nothing was changed. Codes: `queue_unavailable` (a background job could not be enqueued; retry the call), `billing_unavailable` (Stripe would not open a checkout session; nothing was charged, retry the call), `service_unavailable` (the rate-limit store is down, so the request was refused before running).

---

[API](https://skmtc.dev/inkseal/apis/inkseal-api.md) · [All operations](https://skmtc.dev/inkseal/apis/inkseal-api/llms.txt) · [OpenAPI document](https://skmtc.dev/inkseal/apis/inkseal-api/revisions/c440c981d578?raw)
