{
  "openapi": "3.1.0",
  "info": {
    "title": "Siglio API",
    "version": "1.0.0",
    "summary": "Send a document for signature by email, text, or both, in one call.",
    "description": "Siglio is an e-signature API. You send a PDF with signature tags in it, Siglio delivers it to the signer by email or SMS, and you get the signed PDF and an audit certificate back.\n\nTwo things surprise people on their first integration:\n\n1. **Signature placement comes from tags inside the PDF, not from coordinates in the request.** You put `^S1` where signature one goes, `^I1` for initials, `^D1` for a date that fills itself. Those tags must be in WHITE font, or they print on the finished document as visible carets.\n2. **Field values are never returned as data.** Anything a signer types exists only rendered on the signed PDF. Do not build a flow that expects to read it back.\n\nPricing is 25 cents per envelope with no monthly fee. New accounts get 25 free sandbox envelopes.",
    "contact": { "name": "Siglio support", "url": "https://esigndev.com/contact" },
    "license": { "name": "Proprietary", "identifier": "LicenseRef-Proprietary" }
  },
  "servers": [
    { "url": "https://api.esigndev.com", "description": "Production" }
  ],
  "security": [ { "apiKey": [] } ],
  "tags": [
    { "name": "Envelopes", "description": "An envelope is one document sent to one or two signers." },
    { "name": "Uploads", "description": "For PDFs too large to inline in the request body." }
  ],
  "paths": {
    "/v1/envelopes": {
      "post": {
        "operationId": "createEnvelope",
        "summary": "Create and send an envelope",
        "description": "Creates an envelope and delivers it immediately. The PDF must already contain the signature tags; Siglio does not place them for you.\n\nSupply the document one of two ways: `document_base64` for files up to about 3 MB, or `document_id` from POST /v1/uploads for anything larger, up to 15 MB. Exactly one of the two.\n\nSend an `Idempotency-Key` header. A retry with the same key and the same body returns the original envelope instead of sending a second document to the signer.",
        "tags": ["Envelopes"],
        "parameters": [ { "$ref": "#/components/parameters/IdempotencyKey" } ],
        "requestBody": {
          "required": true,
          "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateEnvelopeRequest" },
            "examples": {
              "oneSignerByText": {
                "summary": "One signer, delivered by text",
                "value": { "document_name": "Rental agreement", "document_base64": "JVBERi0xLjcK...", "delivery": "sms",
                  "signer": { "name": "Dana Reyes", "phone": "+18135550142" } }
              },
              "twoSignersMixedChannels": {
                "summary": "Two signers, each on their own channel",
                "value": { "document_name": "Mutual NDA", "document_base64": "JVBERi0xLjcK...", "delivery": "email",
                  "signers": [ { "name": "Dana Reyes", "email": "dana@example.com" },
                               { "name": "Sam Okafor", "phone": "+18135550188", "delivery": "sms" } ] }
              }
            } } }
        },
        "responses": {
          "201": { "description": "Created and delivered.",
            "headers": { "X-Request-Id": { "$ref": "#/components/headers/XRequestId" } },
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "402": { "$ref": "#/components/responses/PaymentRequired" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "422": { "$ref": "#/components/responses/UnprocessableDocument" },
          "429": { "$ref": "#/components/responses/RateLimited" },
          "500": { "$ref": "#/components/responses/InternalError" },
          "503": { "$ref": "#/components/responses/ServiceUnavailable" }
        }
      }
    },
    "/v1/envelopes/{id}": {
      "parameters": [ { "$ref": "#/components/parameters/EnvelopeId" } ],
      "get": {
        "operationId": "getEnvelope",
        "summary": "Retrieve an envelope",
        "description": "Returns the envelope in the same shape the create call returned, with its current state.",
        "tags": ["Envelopes"],
        "responses": {
          "200": { "description": "The envelope.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      },
      "delete": {
        "operationId": "voidEnvelope",
        "summary": "Void an envelope",
        "description": "Cancels an envelope that has not been completed. The signing link stops working immediately and the signer sees a cancellation page. Voiding an already-voided envelope succeeds and changes nothing. A completed envelope cannot be voided. Requires a key with read_write scope.",
        "tags": ["Envelopes"],
        "responses": {
          "200": { "description": "Voided, or already voided.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Envelope" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "403": { "$ref": "#/components/responses/Forbidden" },
          "404": { "$ref": "#/components/responses/NotFound" },
          "422": { "$ref": "#/components/responses/BadRequest" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/v1/envelopes/{id}/document": {
      "parameters": [ { "$ref": "#/components/parameters/EnvelopeId" } ],
      "get": {
        "operationId": "downloadSignedDocument",
        "summary": "Download the signed PDF",
        "description": "Streams the completed, signed PDF. Available only once the envelope reaches `completed`; earlier states return 404. The response is the file itself, not a redirect.",
        "tags": ["Envelopes"],
        "responses": {
          "200": { "description": "The signed PDF.",
            "content": { "application/pdf": { "schema": { "type": "string", "format": "binary" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "404": { "description": "Unknown envelope, or not completed yet.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/v1/uploads": {
      "post": {
        "operationId": "createUpload",
        "summary": "Get a signed URL for a large PDF",
        "description": "For PDFs larger than about 3 MB. Returns a URL to PUT the file to, then pass the returned `id` as `document_id` when creating the envelope.\n\nThe URL expires in 15 minutes, the file must be a PDF of 15 MB or less, and the upload is consumed by a single envelope. Unused uploads are swept after 24 hours.",
        "tags": ["Uploads"],
        "responses": {
          "200": { "description": "Upload target created.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Upload" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    }
  },
  "webhooks": {
    "envelopeEvent": {
      "post": {
        "operationId": "envelopeEvent",
        "summary": "Envelope state change",
        "description": "Sent to your configured endpoint when an envelope's state changes. Events fire on transitions, not activity, so each one arrives once per envelope and never out of order.\n\nVerify the `X-Siglio-Signature` header before trusting the body. Acknowledge quickly with a 2xx and process from your own queue; Siglio does not offer manual replay.\n\n`envelope.partially_signed` means signer one of two has finished. It is NOT done. Only `envelope.completed` means every signature is in.",
        "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/WebhookEvent" } } } },
        "responses": { "200": { "description": "Acknowledged. Any 2xx is treated as delivered." } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http", "scheme": "bearer",
        "description": "Your API key as a bearer token: `Authorization: Bearer sig_sandbox_...`. Keys come from your Siglio account and nowhere else. Sandbox and live keys are separate; a sandbox key creates sandbox envelopes."
      }
    },
    "parameters": {
      "EnvelopeId": { "name": "id", "in": "path", "required": true,
        "description": "The envelope id, e.g. `env_7mmyc1tktzjtjya96cmjbsvb5c`.",
        "schema": { "type": "string", "pattern": "^env_[a-z0-9]+$" } },
      "IdempotencyKey": { "name": "Idempotency-Key", "in": "header", "required": false,
        "description": "Up to 255 characters. Retrying with the same key and body returns the first envelope rather than sending again. The same key with a different body is rejected.",
        "schema": { "type": "string", "maxLength": 255 } }
    },
    "headers": {
      "XRequestId": { "description": "Identifier for this request. Quote it to support.", "schema": { "type": "string" } },
      "RetryAfter": { "description": "Seconds to wait before retrying.", "schema": { "type": "integer" } }
    },
    "schemas": {
      "CreateEnvelopeRequest": {
        "type": "object",
        "required": ["document_name", "delivery"],
        "properties": {
          "document_name": { "type": "string", "description": "What the signer sees this document called." },
          "document_base64": { "type": "string", "description": "The tagged PDF, base64 encoded. Up to about 3 MB. Mutually exclusive with document_id." },
          "document_id": { "type": "string", "description": "An id from POST /v1/uploads, for larger files. Mutually exclusive with document_base64.", "pattern": "^upl_[a-z0-9]+$" },
          "delivery": { "$ref": "#/components/schemas/Delivery" },
          "signer": { "$ref": "#/components/schemas/SignerInput", "description": "One signer. Use this or `signers`, never both." },
          "signers": { "type": "array", "minItems": 1, "maxItems": 2, "items": { "$ref": "#/components/schemas/SignerInput" },
            "description": "One or two signers. Signing is strictly sequential: signer two is not notified until signer one has finished. A PDF tagged for two signers must be sent with two, and vice versa, or the call is rejected." },
          "sender": { "$ref": "#/components/schemas/Sender" }
        }
      },
      "Delivery": { "type": "string", "enum": ["email", "sms", "both"],
        "description": "How the signer is notified. `sms` and `both` require the signer's phone." },
      "SignerInput": {
        "type": "object", "required": ["name"],
        "properties": {
          "name": { "type": "string" },
          "email": { "type": "string", "format": "email", "description": "Required when this signer is reached by email." },
          "phone": { "type": "string", "description": "E.164 preferred, e.g. +18135550142. Required when this signer is reached by text." },
          "delivery": { "$ref": "#/components/schemas/Delivery", "description": "Per-signer override. Defaults to the envelope's delivery." }
        }
      },
      "Sender": {
        "type": "object", "required": ["company_name"],
        "description": "Identifies the business sending this document. It appears on the signer's notifications and on the signature certificate. Any field you omit falls back to the business profile saved on your account, and anything still missing falls back to Siglio.",
        "properties": {
          "company_name": { "type": "string", "maxLength": 100 },
          "phone": { "type": "string", "maxLength": 25 },
          "email": { "type": "string", "format": "email", "maxLength": 254 },
          "address": { "type": "string", "maxLength": 150 },
          "city": { "type": "string", "maxLength": 60 },
          "state": { "type": "string", "maxLength": 30 },
          "zip": { "type": "string", "maxLength": 15 },
          "representative": { "type": "string", "maxLength": 100 }
        }
      },
      "Envelope": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "pattern": "^env_[a-z0-9]+$" },
          "object": { "type": "string", "const": "envelope" },
          "environment": { "type": "string", "enum": ["sandbox", "live"] },
          "state": { "$ref": "#/components/schemas/EnvelopeState" },
          "document_name": { "type": "string" },
          "delivery": { "$ref": "#/components/schemas/Delivery" },
          "signer": { "$ref": "#/components/schemas/Signer", "description": "Signer one. Null only in unusual states." },
          "signers": { "type": "array", "items": { "$ref": "#/components/schemas/Signer" },
            "description": "Present on two-signer envelopes only, with each signer's own signing URL." },
          "signing_url": { "type": ["string", "null"], "description": "Siglio-hosted link for signer one. Safe to share; it never exposes an underlying vendor." },
          "sender": { "$ref": "#/components/schemas/Sender", "description": "Echoed back as resolved, present when sender identity applies." },
          "created_at": { "type": "string", "format": "date-time" },
          "completed_at": { "type": ["string", "null"], "format": "date-time" }
        }
      },
      "Signer": {
        "type": "object",
        "properties": {
          "name": { "type": "string" },
          "email": { "type": ["string", "null"] },
          "phone": { "type": ["string", "null"] },
          "signed_at": { "type": ["string", "null"], "format": "date-time", "description": "When this signer signed. Null means no signature time was recorded for them, not that they have not signed \u2014 on a completed envelope every signer has signed. Never an approximation." },
          "signing_url": { "type": "string", "description": "Present in the `signers` array." }
        }
      },
      "EnvelopeState": {
        "type": "string",
        "enum": ["delivered", "viewed", "partially_signed", "completed", "voided", "failed"],
        "description": "delivered: sent to the signer. viewed: opened. partially_signed: signer one of two has signed, NOT done. completed: every signature is in. voided: cancelled. failed: could not be delivered."
      },
      "Upload": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "pattern": "^upl_[a-z0-9]+$", "description": "Pass as document_id when creating the envelope." },
          "upload_url": { "type": "string", "format": "uri", "description": "PUT the PDF here." },
          "expires_at": { "type": "string", "format": "date-time", "description": "15 minutes from issue." }
        }
      },
      "WebhookEvent": {
        "type": "object",
        "properties": {
          "id": { "type": "string", "pattern": "^evt_[a-z0-9]+$" },
          "type": { "type": "string", "enum": ["envelope.delivered", "envelope.viewed", "envelope.partially_signed", "envelope.completed", "envelope.voided"] },
          "created_at": { "type": "string", "format": "date-time" },
          "data": { "$ref": "#/components/schemas/Envelope" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "type": { "type": "string", "enum": ["authentication_error", "authorization_error", "invalid_request", "invalid_document", "missing_required_tag", "new_envelopes_paused", "account_paused", "self_imposed_cap_reached",
 "usage_limit_reached", "payment_required", "rate_limited", "service_unavailable", "internal_error"] },
              "code": { "type": "string" },
              "message": { "type": "string" },
              "request_id": { "type": ["string", "null"], "description": "Quote this to support." }
            }
          }
        }
      }
    },
    "responses": {
      "BadRequest": { "description": "The request is malformed or contradicts itself.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Unauthorized": { "description": "Missing, unknown, revoked or expired key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "PaymentRequired": { "description": "A card is needed before this call can proceed.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "Forbidden": { "description": "The key lacks the scope, or the account is paused or out of allowance.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "No such envelope on this account.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "UnprocessableDocument": { "description": "The PDF could not be used: unreadable, too large, or its tags do not match the signers supplied.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "RateLimited": { "description": "120 requests per minute per API key.",
        "headers": { "Retry-After": { "$ref": "#/components/headers/RetryAfter" } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "ServiceUnavailable": { "description": "Temporary. Safe to retry with your idempotency key.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "InternalError": { "description": "Our fault. Send us the request_id.",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }
    }
  }
}
