{
  "openapi": "3.1.0",
  "info": {
    "title": "VectorSign API",
    "version": "1.0",
    "description": "\nEverything you need to add legally binding e-signatures to your product: send documents\nfor signature, embed the signing experience in your own app, and get notified the moment\nan agreement is signed.\n\nThe VectorSign API is a JSON REST API over HTTPS. Every response uses the same envelope:\n`{ \"ok\": true, \"data\": … }` on success and `{ \"ok\": false, \"error\": \"…\", \"code\": \"…\" }` on failure.\n\n## Getting API access\n\nAPI credentials are issued per **integration** by the VectorSign team. Each integration\nbelongs to a Business-plan organization: it runs on that organization's plan, its envelopes\ncount toward the organization's monthly allowance, and the organization's owners and admins\ncan see (read-only) every envelope it sends.\n\nWhen your integration is provisioned you receive two secrets, shown **once**:\n\n| Secret | Looks like | Used for |\n|---|---|---|\n| API key | `vsk_live_…` | Authenticating every API request |\n| Webhook secret | `whsec_…` | Verifying the webhooks VectorSign sends you |\n\n[Request API access →](https://calendly.com/vectorviewer/product-demo)\n\n## Authentication\n\nSend your API key in the `X-Api-Key` header on every request. Keep it on your server —\nnever ship it to a browser or mobile app.\n\n```bash\ncurl https://api-sign.vectorviewer.com/api/v1/envelopes \\\n  -H \"X-Api-Key: vsk_live_your_key_here\"\n```\n\n## Quickstart: send your first envelope\n\n**1. Upload the PDF.** Keep the returned metadata — you pass it straight into step 2.\n\n```bash\ncurl -X POST https://api-sign.vectorviewer.com/api/v1/upload \\\n  -H \"X-Api-Key: $VECTORSIGN_API_KEY\" \\\n  -F \"file=@nda.pdf\"\n```\n\n```json\n{ \"ok\": true, \"data\": {\n  \"storage_key\": \"3f1c…-nda.pdf\", \"name\": \"nda.pdf\", \"size_bytes\": 48213,\n  \"page_count\": 3, \"original_hash\": \"9f2a1c…\"\n} }\n```\n\n**2. Create the envelope** with recipients and fields. Fields point at a document by its\n`storage_key` and at a recipient by their email.\n\n```bash\ncurl -X POST https://api-sign.vectorviewer.com/api/v1/envelopes \\\n  -H \"X-Api-Key: $VECTORSIGN_API_KEY\" -H \"Content-Type: application/json\" \\\n  -d '{\n    \"title\": \"Mutual NDA — Acme Corp\",\n    \"message\": \"Please review and sign.\",\n    \"signing_order\": \"sequential\",\n    \"expires_at\": \"2026-12-31T23:59:59Z\",\n    \"reminder_every_days\": 3,\n    \"webhook_url\": \"https://your-app.com/webhooks/vectorsign\",\n    \"source_ref\": \"contract-8812\",\n    \"recipients\": [\n      { \"name\": \"Jamie Sato\", \"email\": \"jamie@acme.com\", \"signing_order\": 1 },\n      { \"name\": \"Legal Team\", \"email\": \"legal@your-co.com\", \"role\": \"cc\" }\n    ],\n    \"documents\": [\n      { \"name\": \"nda.pdf\", \"storage_key\": \"3f1c…-nda.pdf\", \"size_bytes\": 48213,\n        \"page_count\": 3, \"original_hash\": \"9f2a1c…\" }\n    ],\n    \"fields\": [\n      { \"document_id\": \"3f1c…-nda.pdf\", \"recipient_ref\": \"jamie@acme.com\",\n        \"type\": \"signature\", \"page_number\": 3,\n        \"x_pct\": 10, \"y_pct\": 78, \"width_pct\": 20, \"height_pct\": 7 },\n      { \"document_id\": \"3f1c…-nda.pdf\", \"recipient_ref\": \"jamie@acme.com\",\n        \"type\": \"date\", \"page_number\": 3,\n        \"x_pct\": 10, \"y_pct\": 86, \"width_pct\": 18, \"height_pct\": 5 }\n    ]\n  }'\n```\n\n**3. Send it.** Signers are emailed (one at a time for `sequential`, all at once for `parallel`).\n\n```bash\ncurl -X POST https://api-sign.vectorviewer.com/api/v1/envelopes/$ENVELOPE_ID/send \\\n  -H \"X-Api-Key: $VECTORSIGN_API_KEY\"\n```\n\n**4. Get notified.** VectorSign POSTs to your `webhook_url` when the envelope is completed\nor expires — or poll `GET /envelopes/{id}`. Once completed, download the signed\nPDFs with `GET /envelopes/{id}/download-all`.\n\n## Placing fields\n\nField positions are **percentages of the page**, measured from the top-left corner, so\nthey're independent of page size and resolution.\n\n| Property | Meaning |\n|---|---|\n| `page_number` | 1-based page within the document |\n| `x_pct`, `y_pct` | Top-left corner of the field, 0–100 |\n| `width_pct`, `height_pct` | Field size, 1–100 |\n| `document_id` | The `storage_key` returned by `POST /upload` |\n| `recipient_ref` | The email of a recipient with role `signer` |\n| `required` | Defaults to `true`; optional fields can be left empty |\n\n| Type | What the signer does |\n|---|---|\n| `signature` | Draws, types or uploads their signature |\n| `initials` | Adds their initials |\n| `date` | Nothing — **Date signed** is filled in by VectorSign at the moment they finish, in their time zone, and can't be backdated |\n| `fullName` | Confirms their full legal name |\n| `textInput` | Types free text (use `label` for the prompt, e.g. \"Job title\") |\n| `checkbox` | Ticks a box (use `label`, e.g. \"I agree to the terms\"); a required checkbox must be ticked |\n\n## Recipients, order & security\n\n- **Roles** — `signer` (default) signs; `cc` receives the completed document and has no fields.\n- **Signing order** — `sequential` emails each signer after the previous one signs, in\n  `signing_order`; `parallel` emails everyone at once.\n- **Access codes** — set `access_code` (4–32 characters) on a recipient and share it with them\n  out of band (phone, text). They must enter it before the document opens; five wrong\n  attempts lock them out.\n- **Reminders & expiry** — `reminder_every_days` (1–30) re-emails whoever's turn it is, up to\n  five times. After `expires_at` the envelope moves to `expired` and can no longer be signed.\n- **Limits per envelope** — up to 50 recipients, 20 documents and 500 fields. The number of\n  signers is also capped by your organization's plan.\n\n## Embedded signing\n\nKeep signers inside your own app instead of sending them to their inbox.\n\n1. Create the envelope with `\"metadata\": { \"embedded\": true }` — VectorSign then sends **no**\n   signing or reminder emails for it.\n2. Send it as usual, then fetch a signer's personal link:\n   `GET /envelopes/{id}/recipient-signing-url?email=jamie@acme.com`\n3. Open `signing_url` in an iframe or redirect the signer to it.\n4. When they finish, the signing page posts `{ \"type\": \"vectorsign:signed\" }` to\n   `window.parent`, and your webhook fires once every signer is done.\n\n```js\nwindow.addEventListener('message', (e) => {\n  if (e.data?.type === 'vectorsign:signed') closeSigningModal();\n});\n```\n\nTo send signers back to your app after signing instead, append\n`?return_url=https://your-app.com/done` to the signing URL. Return URLs must be HTTPS on a\ndomain we've allow-listed for your integration — contact us to add yours.\n\n## Webhooks\n\nSet `webhook_url` when you create an envelope. VectorSign sends an HTTPS `POST` with a JSON\nbody for these events:\n\n| Event | When |\n|---|---|\n| `envelope.completed` | Every signer has signed; the certificate is ready |\n| `envelope.expired` | `expires_at` passed before everyone signed |\n\nEvery request carries these headers:\n\n| Header | Value |\n|---|---|\n| `X-VectorSign-Event` | The event name |\n| `X-VectorSign-Delivery` | Unique delivery ID — identical across retries, use it to de-duplicate |\n| `X-VectorSign-Signature` | `sha256=` + HMAC-SHA256 of the raw body, keyed with your webhook secret |\n\n**Always verify the signature** against the raw request body before trusting a webhook:\n\n```js\nimport crypto from 'crypto';\n\nfunction isFromVectorSign(rawBody, signatureHeader, webhookSecret) {\n  const expected = 'sha256=' + crypto.createHmac('sha256', webhookSecret)\n    .update(rawBody, 'utf8').digest('hex');\n  return signatureHeader?.length === expected.length &&\n    crypto.timingSafeEqual(Buffer.from(signatureHeader), Buffer.from(expected));\n}\n```\n\nRespond with any `2xx` within 10 seconds. Failed deliveries are retried three times, after 1\nsecond, 5 seconds and 30 seconds.\n\n```json\n{\n  \"event\": \"envelope.completed\",\n  \"timestamp\": \"2026-09-24T10:41:07.000Z\",\n  \"envelope_id\": \"8b2e…\",\n  \"tenant_id\": \"c41a…\",\n  \"source_ref\": \"contract-8812\",\n  \"data\": {\n    \"status\": \"completed\",\n    \"completed_at\": \"2026-09-24T10:41:07.000Z\",\n    \"recipients\": [\n      { \"id\": \"e0d9…\", \"name\": \"Jamie Sato\", \"email\": \"jamie@acme.com\", \"status\": \"signed\" }\n    ]\n  }\n}\n```\n\n## Envelope lifecycle\n\n`draft` → `sent` → `delivered` (a signer opened it) → one of `completed`,\n`voided` (cancelled by you) or `expired`.\n\n## Proof & verification\n\nEvery completed envelope comes with evidence you can check independently:\n\n- `GET /envelopes/{id}/audit` — the append-only audit trail (who did what, when, from which IP).\n- `GET /envelopes/{id}/certificate` — the Certificate of Completion: SHA-256 hashes of every\n  signed document and of the audit trail, plus an **RFC 3161 timestamp** from DigiCert per document.\n- `GET /envelopes/{id}/verify` — re-hashes the stored PDFs and reports any tampering.\n\nYou can verify a timestamp yourself, without trusting VectorSign:\n\n```bash\nopenssl ts -verify -in document.tsr -data signed.pdf -CAfile DigiCertTSACA.crt\n```\n\n## Errors\n\n| Status | Meaning |\n|---|---|\n| `400` | The request body or query is invalid |\n| `401` | Missing or invalid API key |\n| `403` | Not allowed for this envelope (e.g. managing another integration's envelope) |\n| `404` | Envelope or recipient not found |\n| `409` | The envelope isn't in a state that allows this (e.g. voiding a completed envelope) |\n| `422` | Semantically invalid (e.g. unknown category, fields on a CC recipient, too many signers for your plan) |\n| `429` | Rate limit or monthly document limit reached |\n\n## Rate limits\n\nRequests are limited per client IP: **200 per minute** overall, and **30 per minute** on the\nenvelope and upload endpoints. Over the limit you'll get `429` with code `RATE_LIMITED` —\nback off and retry. Need more? Talk to us.\n\n## Usage & plans\n\nEvery envelope you create counts once toward your organization's monthly allowance, shared\nwith the envelopes your organization's members send from the app. Check where you stand with\n`GET /envelopes/usage`.",
    "contact": {
      "name": "VectorSign",
      "url": "https://vectorsign.io/developers/"
    }
  },
  "servers": [
    {
      "url": "https://api-sign.vectorviewer.com/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "ApiKey": []
    }
  ],
  "tags": [
    {
      "name": "Documents",
      "description": "Upload PDFs and download signed copies."
    },
    {
      "name": "Envelopes",
      "description": "Create, send and manage signing requests."
    },
    {
      "name": "Embedded signing",
      "description": "Sign inside your own app."
    },
    {
      "name": "Proof & verification",
      "description": "Audit trail, certificate and tamper checks."
    },
    {
      "name": "Account",
      "description": "Usage against your plan."
    }
  ],
  "paths": {
    "/upload": {
      "post": {
        "tags": [
          "Documents"
        ],
        "summary": "Upload a PDF",
        "operationId": "uploadDocument",
        "description": "Uploads a PDF (max 50 MB). Pass the returned object in `documents[]` when creating an envelope.",
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "type": "object",
                "required": [
                  "file"
                ],
                "properties": {
                  "file": {
                    "type": "string",
                    "format": "binary"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/UploadResult"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Not a PDF, or no file",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes": {
      "post": {
        "tags": [
          "Envelopes"
        ],
        "summary": "Create an envelope",
        "operationId": "createEnvelope",
        "description": "Creates a **draft** envelope with its recipients, documents and fields. Nothing is emailed until you call `send`.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateEnvelope"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Draft created",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Envelope"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Invalid body",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Too many signers for the plan, unknown category, or fields on a CC recipient",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Monthly document limit reached, or rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "get": {
        "tags": [
          "Envelopes"
        ],
        "summary": "List envelopes",
        "operationId": "listEnvelopes",
        "description": "Envelopes your integration created, newest first.",
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Comma-separated statuses, e.g. `sent,delivered`"
          },
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string"
            },
            "description": "Search title, recipient name or email"
          },
          {
            "name": "hide_voided",
            "in": "query",
            "schema": {
              "type": "boolean"
            }
          },
          {
            "name": "page",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 1
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "data": {
                          "type": "array",
                          "items": {
                            "$ref": "#/components/schemas/EnvelopeSummary"
                          }
                        },
                        "meta": {
                          "type": "object",
                          "properties": {
                            "total": {
                              "type": "integer"
                            },
                            "page": {
                              "type": "integer"
                            },
                            "limit": {
                              "type": "integer"
                            },
                            "pages": {
                              "type": "integer"
                            },
                            "counts": {
                              "type": "object",
                              "description": "Envelope count per status"
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}": {
      "get": {
        "tags": [
          "Envelopes"
        ],
        "summary": "Get an envelope",
        "operationId": "getEnvelope",
        "description": "The envelope with its recipients (and their status), documents and fields.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Envelope"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Envelope not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/send": {
      "post": {
        "tags": [
          "Envelopes"
        ],
        "summary": "Send an envelope",
        "operationId": "sendEnvelope",
        "description": "Moves a draft to `sent` and emails the first signer (sequential) or every signer (parallel). Embedded envelopes send no email.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Envelope"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Not a draft",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Envelope not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/void": {
      "put": {
        "tags": [
          "Envelopes"
        ],
        "summary": "Void an envelope",
        "operationId": "voidEnvelope",
        "description": "Cancels an envelope that hasn't completed. It can no longer be signed.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "reason"
                ],
                "properties": {
                  "reason": {
                    "type": "string",
                    "maxLength": 1000
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Envelope"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Already completed or voided",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Envelope not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/remind": {
      "post": {
        "tags": [
          "Envelopes"
        ],
        "summary": "Remind a signer",
        "operationId": "remindSigner",
        "description": "Re-sends the signing email to a signer whose turn it is. Limited to once every 5 minutes per signer.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "recipient_id"
                ],
                "properties": {
                  "recipient_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "sent": {
                          "type": "boolean"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Not awaiting this signer",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Envelope not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/signing-order": {
      "put": {
        "tags": [
          "Envelopes"
        ],
        "summary": "Change signing order",
        "operationId": "changeSigningOrder",
        "description": "Switches an in-flight envelope between sequential and parallel. Switching to parallel immediately emails every signer still waiting their turn.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "signing_order"
                ],
                "properties": {
                  "signing_order": {
                    "type": "string",
                    "enum": [
                      "sequential",
                      "parallel"
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Envelope"
                    }
                  }
                }
              }
            }
          },
          "409": {
            "description": "Envelope not in progress",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Envelope not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/recipient-signing-url": {
      "get": {
        "tags": [
          "Embedded signing"
        ],
        "summary": "Get a signer's signing URL",
        "operationId": "getSigningUrl",
        "description": "For embedded signing: the personal signing link for one signer, to open in an iframe or redirect to.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "email",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "format": "email"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "signing_url": {
                          "type": "string",
                          "format": "uri"
                        },
                        "status": {
                          "type": "string",
                          "description": "The signer's status"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "No signer with that email",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/audit": {
      "get": {
        "tags": [
          "Proof & verification"
        ],
        "summary": "Get the audit trail",
        "operationId": "getAuditTrail",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "array",
                      "items": {
                        "$ref": "#/components/schemas/AuditEvent"
                      }
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Envelope not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/certificate": {
      "get": {
        "tags": [
          "Proof & verification"
        ],
        "summary": "Get the Certificate of Completion",
        "operationId": "getCertificate",
        "description": "Available once the envelope completes.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/Certificate"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Not completed yet",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/verify": {
      "get": {
        "tags": [
          "Proof & verification"
        ],
        "summary": "Verify document integrity",
        "operationId": "verifyEnvelope",
        "description": "Re-hashes each stored signed PDF and compares it with the hash recorded at signing.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "$ref": "#/components/schemas/VerifyResult"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Envelope not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/{id}/download-all": {
      "get": {
        "tags": [
          "Documents"
        ],
        "summary": "Download all documents",
        "operationId": "downloadAll",
        "description": "A ZIP of every document — the signed copies once completed, the originals before.",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Envelope ID",
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "ZIP archive",
            "content": {
              "application/zip": {
                "schema": {
                  "type": "string",
                  "format": "binary"
                }
              }
            }
          },
          "404": {
            "description": "Envelope not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/envelopes/usage": {
      "get": {
        "tags": [
          "Account"
        ],
        "summary": "Get monthly usage",
        "operationId": "getUsage",
        "description": "Envelopes created this month against your organization's plan allowance (shared with the organization's members).",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "ok",
                    "data"
                  ],
                  "properties": {
                    "ok": {
                      "type": "boolean",
                      "const": true
                    },
                    "data": {
                      "type": "object",
                      "properties": {
                        "used": {
                          "type": "integer"
                        },
                        "limit": {
                          "type": "integer"
                        },
                        "plan": {
                          "type": "string"
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "429": {
            "description": "Rate limited",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    }
  },
  "webhooks": {
    "envelopeEvent": {
      "post": {
        "summary": "Envelope completed or expired",
        "description": "Sent to the envelope's `webhook_url`. Verify `X-VectorSign-Signature` before trusting it.",
        "parameters": [
          {
            "name": "X-VectorSign-Event",
            "in": "header",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "X-VectorSign-Delivery",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "Same across retries"
          },
          {
            "name": "X-VectorSign-Signature",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "sha256=<hex HMAC of the raw body>"
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookEvent"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledge within 10 seconds"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {
        "type": "apiKey",
        "in": "header",
        "name": "X-Api-Key",
        "description": "Your integration's API key (`vsk_live_…`)."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "properties": {
          "ok": {
            "type": "boolean",
            "const": false
          },
          "error": {
            "type": "string",
            "description": "Human-readable message",
            "examples": [
              "Envelope not found"
            ]
          },
          "code": {
            "type": "string",
            "description": "Machine-readable code",
            "examples": [
              "NOT_FOUND"
            ]
          }
        }
      },
      "UploadResult": {
        "type": "object",
        "description": "Pass these fields straight into `documents[]` when creating an envelope.",
        "properties": {
          "storage_key": {
            "type": "string",
            "description": "Reference to the uploaded file — also used as `document_id` on fields"
          },
          "name": {
            "type": "string"
          },
          "size_bytes": {
            "type": "integer"
          },
          "page_count": {
            "type": "integer"
          },
          "original_hash": {
            "type": "string",
            "description": "SHA-256 of the file (hex)"
          }
        }
      },
      "RecipientInput": {
        "type": "object",
        "required": [
          "name",
          "email"
        ],
        "properties": {
          "name": {
            "type": "string",
            "maxLength": 255
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "role": {
            "type": "string",
            "enum": [
              "signer",
              "cc"
            ],
            "default": "signer",
            "description": "`cc` recipients receive the completed document and can't have fields"
          },
          "signing_order": {
            "type": "integer",
            "minimum": 1,
            "description": "Position in a sequential envelope"
          },
          "access_code": {
            "type": "string",
            "minLength": 4,
            "maxLength": 32,
            "description": "Code the recipient must enter before the document opens. Share it out of band."
          }
        }
      },
      "DocumentInput": {
        "type": "object",
        "required": [
          "name",
          "storage_key",
          "size_bytes",
          "page_count",
          "original_hash"
        ],
        "properties": {
          "name": {
            "type": "string"
          },
          "storage_key": {
            "type": "string"
          },
          "size_bytes": {
            "type": "integer"
          },
          "page_count": {
            "type": "integer"
          },
          "original_hash": {
            "type": "string",
            "pattern": "^[a-f0-9]{64}$"
          },
          "order_index": {
            "type": "integer",
            "minimum": 0
          }
        }
      },
      "FieldInput": {
        "type": "object",
        "required": [
          "document_id",
          "recipient_ref",
          "type",
          "page_number",
          "x_pct",
          "y_pct",
          "width_pct",
          "height_pct"
        ],
        "properties": {
          "document_id": {
            "type": "string",
            "description": "The document's `storage_key`"
          },
          "recipient_ref": {
            "type": "string",
            "description": "Email of a recipient with role `signer`"
          },
          "type": {
            "type": "string",
            "enum": [
              "signature",
              "initials",
              "date",
              "fullName",
              "textInput",
              "checkbox"
            ],
            "description": "`date` is Date signed — filled in automatically when the signer finishes"
          },
          "page_number": {
            "type": "integer",
            "minimum": 1
          },
          "x_pct": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "y_pct": {
            "type": "number",
            "minimum": 0,
            "maximum": 100
          },
          "width_pct": {
            "type": "number",
            "minimum": 1,
            "maximum": 100
          },
          "height_pct": {
            "type": "number",
            "minimum": 1,
            "maximum": 100
          },
          "required": {
            "type": "boolean",
            "default": true
          },
          "label": {
            "type": "string",
            "description": "Shown to the signer, e.g. \"I agree to the terms\""
          }
        }
      },
      "CreateEnvelope": {
        "type": "object",
        "required": [
          "title",
          "recipients",
          "documents",
          "fields"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 500
          },
          "message": {
            "type": "string",
            "maxLength": 5000,
            "description": "Included in the signing email"
          },
          "signing_order": {
            "type": "string",
            "enum": [
              "sequential",
              "parallel"
            ],
            "default": "sequential"
          },
          "expires_at": {
            "type": "string",
            "format": "date-time",
            "description": "After this the envelope expires and can't be signed"
          },
          "reminder_every_days": {
            "type": [
              "integer",
              "null"
            ],
            "minimum": 1,
            "maximum": 30,
            "description": "Automatic reminders to whoever's turn it is (max 5). Omit or null for none."
          },
          "webhook_url": {
            "type": "string",
            "format": "uri",
            "description": "Receives envelope.completed and envelope.expired"
          },
          "source_ref": {
            "type": "string",
            "description": "Your own ID for this agreement — echoed back in webhooks"
          },
          "category": {
            "type": "string",
            "maxLength": 60,
            "description": "Name of one of your organization's envelope categories (case-insensitive)"
          },
          "metadata": {
            "type": "object",
            "additionalProperties": true,
            "description": "Free-form. Set `{ \"embedded\": true }` to suppress signing emails for embedded signing."
          },
          "recipients": {
            "type": "array",
            "minItems": 1,
            "maxItems": 50,
            "items": {
              "$ref": "#/components/schemas/RecipientInput"
            }
          },
          "documents": {
            "type": "array",
            "minItems": 1,
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/DocumentInput"
            }
          },
          "fields": {
            "type": "array",
            "maxItems": 500,
            "items": {
              "$ref": "#/components/schemas/FieldInput"
            }
          }
        }
      },
      "Recipient": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "signer",
              "cc",
              "viewer"
            ]
          },
          "signing_order": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "sent",
              "viewed",
              "signed",
              "declined"
            ],
            "description": "`pending` = not their turn yet"
          },
          "viewed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "signed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "declined_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "decline_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "has_access_code": {
            "type": "boolean"
          }
        }
      },
      "Document": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "page_count": {
            "type": "integer"
          },
          "size_bytes": {
            "type": "integer"
          },
          "original_hash": {
            "type": "string"
          },
          "order_index": {
            "type": "integer"
          },
          "signed_storage_key": {
            "type": [
              "string",
              "null"
            ],
            "description": "Set once the envelope is completed"
          }
        }
      },
      "Envelope": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "message": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "sent",
              "delivered",
              "completed",
              "declined",
              "voided",
              "expired"
            ]
          },
          "signing_order": {
            "type": "string",
            "enum": [
              "sequential",
              "parallel"
            ]
          },
          "source_ref": {
            "type": [
              "string",
              "null"
            ]
          },
          "metadata": {
            "type": "object"
          },
          "reminder_every_days": {
            "type": [
              "integer",
              "null"
            ]
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "voided_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "void_reason": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "recipients": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Recipient"
            }
          },
          "documents": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Document"
            }
          },
          "fields": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "EnvelopeSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "string"
          },
          "signing_order": {
            "type": "string"
          },
          "category_name": {
            "type": [
              "string",
              "null"
            ]
          },
          "sent_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "expires_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AuditEvent": {
        "type": "object",
        "properties": {
          "event": {
            "type": "string",
            "examples": [
              "recipient.email_sent",
              "recipient.signing_url_opened",
              "field.signed",
              "recipient.signed",
              "envelope.completed"
            ]
          },
          "actor_type": {
            "type": "string",
            "enum": [
              "system",
              "sender",
              "recipient",
              "api"
            ]
          },
          "actor_email": {
            "type": [
              "string",
              "null"
            ]
          },
          "ip_address": {
            "type": [
              "string",
              "null"
            ]
          },
          "metadata": {
            "type": "object"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Certificate": {
        "type": "object",
        "properties": {
          "schema_version": {
            "type": "string"
          },
          "certificate_type": {
            "type": "string",
            "examples": [
              "VectorSign Certificate of Completion"
            ]
          },
          "generated_at": {
            "type": "string",
            "format": "date-time"
          },
          "integrity": {
            "type": "object",
            "properties": {
              "algorithm": {
                "type": "string",
                "examples": [
                  "SHA-256"
                ]
              },
              "document_hash": {
                "type": "string"
              },
              "audit_log_hash": {
                "type": "string"
              },
              "combined_hash": {
                "type": "string"
              }
            }
          },
          "documents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "hash": {
                  "type": "string"
                },
                "signed": {
                  "type": "boolean"
                },
                "timestamp": {
                  "type": [
                    "object",
                    "null"
                  ],
                  "description": "RFC 3161 timestamp from DigiCert, with how-to-verify instructions"
                }
              }
            }
          },
          "audit_trail": {
            "type": "array",
            "items": {
              "type": "object"
            }
          }
        }
      },
      "VerifyResult": {
        "type": "object",
        "properties": {
          "verified": {
            "type": "boolean",
            "description": "True only if every document is signed and unmodified"
          },
          "envelope_title": {
            "type": "string"
          },
          "completed_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "documents": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string"
                },
                "verified": {
                  "type": "boolean"
                },
                "tampered": {
                  "type": "boolean"
                },
                "stored_hash": {
                  "type": "string"
                },
                "current_hash": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "event": {
            "type": "string",
            "enum": [
              "envelope.completed",
              "envelope.expired"
            ]
          },
          "timestamp": {
            "type": "string",
            "format": "date-time"
          },
          "envelope_id": {
            "type": "string",
            "format": "uuid"
          },
          "tenant_id": {
            "type": "string",
            "format": "uuid"
          },
          "source_ref": {
            "type": [
              "string",
              "null"
            ],
            "description": "Your `source_ref` from creation"
          },
          "data": {
            "type": "object",
            "description": "completed: `{ status, completed_at, recipients[] }` · expired: `{ status }`"
          }
        }
      }
    }
  }
}