{"openapi": "3.1.0", "info": {"title": "EasySign API", "version": "1.0.0", "summary": "Send documents for e-signature, track them and get signed webhooks.", "description": "Authenticate with an organisation API key (Settings > Developers):\n`Authorization: Bearer es_live_...`. Keys carry scopes; a call without\nthe scope it needs gets 403 `insufficient_scope`. Each key may make 120\nrequests per minute (429 with `Retry-After`).\n\nPOST requests accept an `Idempotency-Key` header (up to 64 characters).\nRepeating a request with the same key within 24 hours returns the first\nresponse (header `Idempotent-Replayed: true`); the same key with a\ndifferent body returns 409 `idempotency_conflict`.\n\nErrors are JSON: `{\"error\": \"<code>\", \"message\": \"<for people>\", ...}`;\nvalidation errors (422) add `errors: [..]`.\n\nThe API, webhooks and MCP are on paid plans (Starter and above); keys of\nan organisation on the Free plan get 402 `plan_required`. Each plan has a\nmonthly document allowance (429 `plan_limit` when it's used up).\n\nUntil the organisation's business is verified, documents can only be\nsent to the organisation's own members (403 `profile_unverified`).\nAPI keys can prepare and send documents; they can never sign them.\n"}, "servers": [{"url": "https://api.easysignit.com", "description": "Production"}, {"url": "https://api-dev.easysignit.com", "description": "Development (test keys, es_test_...)"}], "security": [{"apiKey": []}], "tags": [{"name": "Documents"}, {"name": "Envelopes"}, {"name": "Templates"}, {"name": "Webhooks"}], "paths": {"/v1/openapi.json": {"get": {"operationId": "getOpenApi", "summary": "This document", "security": [], "responses": {"200": {"description": "The OpenAPI document.", "content": {"application/json": {"schema": {"type": "object"}}}}}}}, "/v1/documents/upload-url": {"post": {"operationId": "createUploadUrl", "tags": ["Documents"], "summary": "Get a URL to upload a PDF", "description": "Scope `documents:write`. PUT the PDF bytes to `url` with `headers`\nbefore `expires_in` seconds, then call `POST /v1/documents`.\n", "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "responses": {"200": {"description": "Upload slot.", "content": {"application/json": {"schema": {"type": "object", "required": ["upload_id", "url", "headers", "max_bytes", "expires_in"], "properties": {"upload_id": {"type": "string", "examples": ["up_abc123"]}, "url": {"type": "string", "format": "uri"}, "headers": {"type": "object", "additionalProperties": {"type": "string"}}, "max_bytes": {"type": "integer"}, "expires_in": {"type": "integer"}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/documents": {"post": {"operationId": "createDocument", "tags": ["Documents"], "summary": "Turn an upload into a document", "description": "Scope `documents:write`. The PDF is checked and normalised (scripts,\nactions and forms removed). Encrypted, malformed, larger than 20 MB\nor longer than 100 pages: 422 `pdf_rejected` with `reason`.\n", "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "required": ["upload_id"], "properties": {"upload_id": {"type": "string"}, "name": {"type": "string", "maxLength": 200}}}}}}, "responses": {"201": {"description": "Stored document.", "content": {"application/json": {"schema": {"type": "object", "properties": {"document": {"$ref": "#/components/schemas/Document"}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/envelopes": {"post": {"operationId": "createEnvelope", "tags": ["Envelopes"], "summary": "Send a document for signature", "description": "Scope `envelopes:write`. Either `template_id` + one recipient per\ntemplate role, or `kind: \"pdf\"` with `document_id`, `title`,\n`recipients` and `fields`. Recipients are emailed their signing\nlinks straight away.\n", "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"oneOf": [{"$ref": "#/components/schemas/TemplateSend"}, {"$ref": "#/components/schemas/PdfSend"}]}}}}, "responses": {"201": {"$ref": "#/components/responses/EnvelopeCreated"}, "default": {"$ref": "#/components/responses/Error"}}}, "get": {"operationId": "listEnvelopes", "tags": ["Envelopes"], "summary": "List envelopes", "description": "Scope `envelopes:read`. Newest first.", "parameters": [{"name": "status", "in": "query", "schema": {"type": "string", "enum": ["sent", "completed", "declined", "voided", "expired"]}}, {"name": "q", "in": "query", "description": "Search title, document name, recipient names and emails.", "schema": {"type": "string", "maxLength": 100}}, {"name": "business_id", "in": "query", "schema": {"type": "string"}}, {"name": "limit", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 50}}, {"name": "cursor", "in": "query", "schema": {"type": "string"}}], "responses": {"200": {"description": "A page of envelopes.", "content": {"application/json": {"schema": {"type": "object", "properties": {"envelopes": {"type": "array", "items": {"$ref": "#/components/schemas/Envelope"}}, "next_cursor": {"type": ["string", "null"]}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/envelopes/{id}": {"get": {"operationId": "getEnvelope", "tags": ["Envelopes"], "summary": "Get an envelope and its audit trail", "description": "Scope `envelopes:read`.", "parameters": [{"$ref": "#/components/parameters/EnvelopeId"}], "responses": {"200": {"description": "The envelope.", "content": {"application/json": {"schema": {"type": "object", "properties": {"envelope": {"$ref": "#/components/schemas/Envelope"}, "events": {"type": "array", "items": {"$ref": "#/components/schemas/AuditEvent"}}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/envelopes/{id}/void": {"post": {"operationId": "voidEnvelope", "tags": ["Envelopes"], "summary": "Void (cancel) an envelope", "description": "Scope `envelopes:write`. Only while it is waiting for signatures.", "parameters": [{"$ref": "#/components/parameters/EnvelopeId"}, {"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"type": "object", "required": ["reason"], "properties": {"reason": {"type": "string", "maxLength": 500}}}}}}, "responses": {"200": {"$ref": "#/components/responses/EnvelopeOk"}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/envelopes/{id}/signed-pdf": {"get": {"operationId": "getSignedPdf", "tags": ["Envelopes"], "summary": "Download URL for the signed PDF", "description": "Scope `envelopes:read`. Completed envelopes only; the URL works for 5 minutes.", "parameters": [{"$ref": "#/components/parameters/EnvelopeId"}], "responses": {"200": {"$ref": "#/components/responses/Url"}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/envelopes/{id}/certificate": {"get": {"operationId": "getCertificate", "tags": ["Envelopes"], "summary": "Download URL for the certificate of completion", "description": "Scope `envelopes:read`. Completed envelopes only; the URL works for 5 minutes.", "parameters": [{"$ref": "#/components/parameters/EnvelopeId"}], "responses": {"200": {"$ref": "#/components/responses/Url"}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/templates": {"get": {"operationId": "listTemplates", "tags": ["Templates"], "summary": "List templates", "description": "Scope `templates:read`.", "responses": {"200": {"description": "Templates this key can use.", "content": {"application/json": {"schema": {"type": "object", "properties": {"templates": {"type": "array", "items": {"$ref": "#/components/schemas/Template"}}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/templates/{id}/send": {"post": {"operationId": "sendTemplate", "tags": ["Templates"], "summary": "Send a template", "description": "Scope `templates:send`. One recipient per template role.", "parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}, {"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/TemplateSendBody"}}}}, "responses": {"201": {"$ref": "#/components/responses/EnvelopeCreated"}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/webhooks": {"get": {"operationId": "listWebhooks", "tags": ["Webhooks"], "summary": "List webhook endpoints", "description": "Scope `webhooks:manage`.", "responses": {"200": {"description": "Endpoints and the event types you can subscribe to.", "content": {"application/json": {"schema": {"type": "object", "properties": {"webhooks": {"type": "array", "items": {"$ref": "#/components/schemas/Webhook"}}, "events": {"type": "array", "items": {"type": "string"}}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}, "post": {"operationId": "createWebhook", "tags": ["Webhooks"], "summary": "Add a webhook endpoint", "description": "Scope `webhooks:manage`. At most 10 per organisation. The signing\n`secret` is returned only here: store it.\n", "parameters": [{"$ref": "#/components/parameters/IdempotencyKey"}], "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebhookInput"}}}}, "responses": {"201": {"description": "Created.", "content": {"application/json": {"schema": {"type": "object", "properties": {"webhook": {"$ref": "#/components/schemas/Webhook"}, "secret": {"type": "string", "examples": ["whsec_..."]}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}}, "/v1/webhooks/{id}": {"parameters": [{"name": "id", "in": "path", "required": true, "schema": {"type": "string"}}], "get": {"operationId": "getWebhook", "tags": ["Webhooks"], "summary": "Get an endpoint and its last 50 deliveries", "description": "Scope `webhooks:manage`.", "responses": {"200": {"description": "The endpoint.", "content": {"application/json": {"schema": {"type": "object", "properties": {"webhook": {"$ref": "#/components/schemas/Webhook"}, "deliveries": {"type": "array", "items": {"$ref": "#/components/schemas/Delivery"}}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}, "put": {"operationId": "updateWebhook", "tags": ["Webhooks"], "summary": "Update an endpoint", "description": "Scope `webhooks:manage`. Setting `active` true again resets the failure count.", "requestBody": {"required": true, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebhookInput"}}}}, "responses": {"200": {"description": "Updated.", "content": {"application/json": {"schema": {"type": "object", "properties": {"webhook": {"$ref": "#/components/schemas/Webhook"}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}, "delete": {"operationId": "deleteWebhook", "tags": ["Webhooks"], "summary": "Delete an endpoint", "description": "Scope `webhooks:manage`.", "responses": {"200": {"description": "Deleted.", "content": {"application/json": {"schema": {"type": "object", "properties": {"deleted": {"type": "boolean"}}}}}}, "default": {"$ref": "#/components/responses/Error"}}}}}, "webhooks": {"event": {"post": {"summary": "An event EasySign sends to your endpoint", "description": "Headers: `EasySign-Event-Id`, `EasySign-Timestamp` and\n`EasySign-Signature: t=<unix>,v1=<hex>` where `v1` is\nHMAC-SHA256 of `\"<t>.<raw body>\"` keyed with your endpoint secret.\nVerify it, reject old timestamps, answer 2xx within 10 seconds.\nFailed deliveries are retried after 1 m, 5 m, 30 m, 2 h, 6 h and\n12 h; an endpoint failing 20 times in a row is disabled.\n", "requestBody": {"content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebhookEvent"}}}}, "responses": {"200": {"description": "Received."}}}}}, "components": {"securitySchemes": {"apiKey": {"type": "http", "scheme": "bearer", "bearerFormat": "es_<test|live>_<32 characters>"}}, "parameters": {"IdempotencyKey": {"name": "Idempotency-Key", "in": "header", "required": false, "schema": {"type": "string", "maxLength": 64}}, "EnvelopeId": {"name": "id", "in": "path", "required": true, "schema": {"type": "string", "examples": ["env_abc123"]}}}, "responses": {"Error": {"description": "Error.", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/Error"}}}}, "Url": {"description": "A short-lived download URL.", "content": {"application/json": {"schema": {"type": "object", "properties": {"url": {"type": "string", "format": "uri"}}}}}}, "EnvelopeOk": {"description": "The envelope.", "content": {"application/json": {"schema": {"type": "object", "properties": {"envelope": {"$ref": "#/components/schemas/Envelope"}}}}}}, "EnvelopeCreated": {"description": "Created and sent.", "content": {"application/json": {"schema": {"type": "object", "properties": {"envelope": {"$ref": "#/components/schemas/Envelope"}, "warnings": {"type": "array", "items": {"type": "string"}}}}}}}}, "schemas": {"Error": {"type": "object", "required": ["error", "message"], "properties": {"error": {"type": "string", "examples": ["validation", "insufficient_scope", "plan_required", "plan_limit", "rate_limited", "idempotency_conflict", "recipient_suppressed"]}, "message": {"type": "string"}, "errors": {"type": "array", "items": {"type": "string"}}, "retry_after": {"type": "integer"}}}, "Document": {"type": "object", "properties": {"document_id": {"type": "string"}, "name": {"type": "string"}, "sha256": {"type": "string"}, "size": {"type": "integer"}, "created_at": {"type": "string", "format": "date-time"}, "pages": {"type": "array", "items": {"type": "object", "properties": {"width_pt": {"type": "number"}, "height_pt": {"type": "number"}, "rotation": {"type": "integer"}}}}}}, "RecipientInput": {"type": "object", "required": ["name", "email"], "properties": {"id": {"type": "string", "description": "r1, r2, ... (default by position)"}, "role": {"type": "string", "enum": ["signer", "approver", "cc"], "default": "signer"}, "order": {"type": "integer", "minimum": 1, "maximum": 10, "default": 1}, "name": {"type": "string", "maxLength": 120}, "email": {"type": "string", "format": "email"}, "label": {"type": "string", "maxLength": 60, "description": "Their part in the document (\"Buyer\", \"Seller\"). Shown to the recipient (\"sign as Seller\"), to other recipients and to you. Placeholder names like \"Signer 2\" are ignored."}}}, "Field": {"type": "object", "required": ["id", "type", "page", "x", "y", "w", "h"], "description": "Coordinates are fractions (0..1) of the page as displayed, origin top-left.", "properties": {"id": {"type": "string"}, "type": {"type": "string", "enum": ["signature", "initials", "date_signed", "name", "text", "checkbox", "dropdown"]}, "page": {"type": "integer", "minimum": 0}, "x": {"type": "number"}, "y": {"type": "number"}, "w": {"type": "number"}, "h": {"type": "number"}, "recipient": {"type": "string", "description": "A signer's recipient id."}, "required": {"type": "boolean"}, "label": {"type": "string", "maxLength": 100}, "options": {"type": "array", "items": {"type": "string"}}}}, "SendSettings": {"type": "object", "properties": {"title": {"type": "string", "maxLength": 200}, "message": {"type": "string", "maxLength": 2000}, "business_id": {"type": "string"}, "reminder_days": {"type": "integer", "minimum": 0, "maximum": 30, "default": 3}, "expires_in_days": {"type": "integer", "minimum": 1, "maximum": 30, "default": 7}, "hide_completed_values": {"type": "boolean", "default": false, "description": "PDF envelopes: by default people in later steps see what earlier signers entered (values and signatures) before they sign. Set true to show only \"Signed by <name>\" placeholders until completion."}}}, "PdfSend": {"allOf": [{"$ref": "#/components/schemas/SendSettings"}, {"type": "object", "required": ["kind", "document_id", "title", "recipients", "fields"], "properties": {"kind": {"const": "pdf"}, "document_id": {"type": "string"}, "recipients": {"type": "array", "minItems": 1, "maxItems": 10, "items": {"$ref": "#/components/schemas/RecipientInput"}}, "fields": {"type": "array", "items": {"$ref": "#/components/schemas/Field"}}}}]}, "TemplateRecipient": {"type": "object", "required": ["role_id", "name", "email"], "properties": {"role_id": {"type": "string", "description": "The template role this person fills."}, "name": {"type": "string"}, "email": {"type": "string", "format": "email"}}}, "TemplateSendBody": {"allOf": [{"$ref": "#/components/schemas/SendSettings"}, {"type": "object", "required": ["recipients"], "properties": {"recipients": {"type": "array", "items": {"$ref": "#/components/schemas/TemplateRecipient"}}}}]}, "TemplateSend": {"allOf": [{"$ref": "#/components/schemas/TemplateSendBody"}, {"type": "object", "required": ["template_id"], "properties": {"template_id": {"type": "string"}}}]}, "Recipient": {"type": "object", "properties": {"id": {"type": "string"}, "role": {"type": "string", "enum": ["signer", "approver", "cc"]}, "name": {"type": "string"}, "email": {"type": "string"}, "order": {"type": "integer"}, "state": {"type": "string", "enum": ["waiting", "sent", "viewed", "completed", "declined", "notified"]}, "sent_at": {"type": ["string", "null"]}, "viewed_at": {"type": ["string", "null"]}, "completed_at": {"type": ["string", "null"]}, "declined_at": {"type": ["string", "null"]}, "decline_reason": {"type": ["string", "null"]}, "undeliverable": {"type": ["object", "null"], "description": "Set when email to this recipient hard-bounced or was marked as spam.", "properties": {"reason": {"type": "string", "enum": ["bounced", "complaint"]}, "at": {"type": "string"}, "email": {"type": "string"}}}}}, "Envelope": {"type": "object", "properties": {"id": {"type": "string"}, "kind": {"type": "string", "enum": ["form", "pdf"]}, "title": {"type": "string"}, "status": {"type": "string", "enum": ["sent", "completed", "declined", "voided", "expired"]}, "brand_name": {"type": "string"}, "business_id": {"type": ["string", "null"]}, "document_id": {"type": ["string", "null"]}, "message": {"type": ["string", "null"]}, "created_at": {"type": "string"}, "sent_at": {"type": "string"}, "completed_at": {"type": ["string", "null"]}, "voided_at": {"type": ["string", "null"]}, "void_reason": {"type": ["string", "null"]}, "declined_at": {"type": ["string", "null"]}, "decline_reason": {"type": ["string", "null"]}, "expires_at": {"type": "string"}, "pdf_sha256": {"type": ["string", "null"]}, "certificate_sha256": {"type": ["string", "null"]}, "sender_email": {"type": ["string", "null"]}, "reminder_days": {"type": "integer"}, "expires_in_days": {"type": ["integer", "null"]}, "next_reminder_at": {"type": ["string", "null"]}, "needs_attention": {"type": "boolean"}, "hide_completed_values": {"type": "boolean"}, "via": {"type": ["object", "null"], "description": "Set when the envelope was created with an API key (and agent, via MCP).", "properties": {"type": {"const": "api_key"}, "key_id": {"type": "string"}, "key_name": {"type": "string"}, "agent": {"type": "string"}}}, "recipients": {"type": "array", "items": {"$ref": "#/components/schemas/Recipient"}}}}, "AuditEvent": {"type": "object", "properties": {"seq": {"type": "integer"}, "type": {"type": "string"}, "at": {"type": "string"}, "actor": {"type": "object"}, "data": {"type": "object"}, "hash": {"type": "string"}, "prev_hash": {"type": "string"}}}, "Template": {"type": "object", "properties": {"template_id": {"type": "string"}, "name": {"type": "string"}, "title": {"type": ["string", "null"]}, "message": {"type": ["string", "null"]}, "business_id": {"type": ["string", "null"]}, "field_count": {"type": "integer"}, "reminder_days": {"type": ["integer", "null"]}, "expires_in_days": {"type": ["integer", "null"]}, "updated_at": {"type": ["string", "null"]}, "roles": {"type": "array", "items": {"type": "object", "properties": {"role_id": {"type": "string"}, "role": {"type": "string", "enum": ["signer", "approver", "cc"]}, "label": {"type": "string"}, "order": {"type": "integer"}}}}}}, "WebhookInput": {"type": "object", "properties": {"url": {"type": "string", "format": "uri", "maxLength": 500, "description": "https, port 443, public host"}, "description": {"type": "string", "maxLength": 200}, "events": {"type": "array", "description": "[\"*\"] for every event.", "items": {"type": "string", "enum": ["*", "envelope.sent", "envelope.viewed", "recipient.completed", "recipient.declined", "envelope.completed", "envelope.declined", "envelope.voided", "envelope.expired", "recipient.bounced"]}}, "active": {"type": "boolean"}}}, "Webhook": {"type": "object", "properties": {"webhook_id": {"type": "string"}, "url": {"type": "string"}, "description": {"type": "string"}, "events": {"type": "array", "items": {"type": "string"}}, "active": {"type": "boolean"}, "created_at": {"type": "string"}, "updated_at": {"type": "string"}, "failure_streak": {"type": "integer"}, "disabled_reason": {"type": ["string", "null"]}, "last_delivery_at": {"type": ["string", "null"]}, "last_status": {"type": ["string", "null"], "enum": ["delivered", "failed", null]}}}, "Delivery": {"type": "object", "properties": {"event_id": {"type": "string"}, "event_type": {"type": "string"}, "at": {"type": "string"}, "attempt": {"type": "integer"}, "status": {"type": ["integer", "null"]}, "ok": {"type": "boolean"}, "duration_ms": {"type": "integer"}, "error": {"type": "string"}}}, "WebhookEvent": {"type": "object", "required": ["id", "type", "created_at", "data"], "properties": {"id": {"type": "string", "examples": ["evt_..."]}, "type": {"type": "string", "enum": ["ping", "envelope.sent", "envelope.viewed", "recipient.completed", "recipient.declined", "envelope.completed", "envelope.declined", "envelope.voided", "envelope.expired", "recipient.bounced"]}, "created_at": {"type": "string"}, "data": {"type": "object", "properties": {"envelope": {"$ref": "#/components/schemas/Envelope"}, "recipient": {"type": "object", "description": "recipient.* and envelope.viewed/declined events.", "properties": {"id": {"type": "string"}, "role": {"type": "string"}, "name": {"type": "string"}, "email": {"type": "string"}}}, "reason": {"type": "string", "description": "declined/voided reason, or bounced|complaint"}, "webhook_id": {"type": "string", "description": "ping only"}}}}}}}}