{
  "openapi": "3.1.0",
  "info": {
    "title": "SignSealer",
    "version": "1.0.0",
    "description": "Signatures with the evidence behind them.\n\nEvery write that creates something takes an optional `Idempotency-Key`, with Stripe's semantics — the same key and body replays, a different body is refused. Every response carries an `x-request-id`; quote it if you need us to look something up.",
    "contact": {
      "name": "SignSealer",
      "url": "https://signsealer.com"
    }
  },
  "servers": [
    {
      "url": "https://api.signsealer.com"
    }
  ],
  "security": [
    {
      "apiKey": []
    }
  ],
  "components": {
    "securitySchemes": {
      "apiKey": {
        "type": "http",
        "scheme": "bearer",
        "description": "An API key, as `Authorization: Bearer mk_live_…`. Keys are shown once when issued and stored only as their hash. A key is a member of the account: its scopes are its capabilities, and revoking it ends its access in the same statement."
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string"
              },
              "message": {
                "type": "string"
              },
              "hint": {
                "type": "string"
              }
            }
          }
        }
      }
    }
  },
  "tags": [
    {
      "name": "Account",
      "description": "Whose key this is."
    },
    {
      "name": "Templates",
      "description": "The text people sign, and its versions."
    },
    {
      "name": "Documents",
      "description": "One agreement, its signers and its evidence."
    },
    {
      "name": "Workflows",
      "description": "A template plus the rules for running it."
    },
    {
      "name": "Subjects",
      "description": "Reservations and activities, and what each needs signed."
    },
    {
      "name": "Packets",
      "description": "Several documents about one subject, behind one link."
    },
    {
      "name": "Webhooks",
      "description": "Where completions are delivered."
    },
    {
      "name": "Signing",
      "description": "What a person holding a signing link can do. No API key: the token is the credential, and attaching a key would let any member of any tenant sign anything whose token they could guess."
    },
    {
      "name": "Verify",
      "description": "Checking a certificate from its printed code, without an account."
    }
  ],
  "paths": {
    "/v1/account": {
      "get": {
        "operationId": "get-account",
        "summary": "Show the account this key belongs to",
        "description": "The first call any integration makes: prove the credential works and show the operator the name of the account they just connected.",
        "tags": [
          "Account"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "tenant_id": "3a1f…",
                  "name": "Fern Hollow Stables",
                  "slug": "fern-hollow",
                  "key_label": "Booking system",
                  "scopes": [
                    "signing:read",
                    "signing:write"
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/templates": {
      "get": {
        "operationId": "get-templates",
        "summary": "List templates",
        "description": "Every version of every template, newest first, with whether each is published and how many documents were prepared from it.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "templates": [
                    {
                      "template_id": "8c2e…",
                      "code": "liability-waiver",
                      "name": "Liability waiver",
                      "kind": "waiver",
                      "version": 2,
                      "is_published": true,
                      "published_at": "2026-10-03T14:22:09Z",
                      "variables": [
                        "participant_name",
                        "date",
                        "emergency_contact"
                      ],
                      "grants": {},
                      "documents": 412,
                      "is_latest": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "post-templates",
        "summary": "Create a template",
        "description": "Creates version 1, as a draft. A template is not usable until it is published, and publishing is what freezes the text people will have signed.",
        "tags": [
          "Templates"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:templates",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Your own key, 8–255 characters. The same key with the same body replays the first response without doing the work again; the same key with a different body is refused rather than absorbed.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "template_id": "8c2e…"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "code": {
                    "type": "string",
                    "pattern": "^[a-z][a-z0-9_-]*$"
                  },
                  "name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "kind": {
                    "type": "string",
                    "enum": [
                      "nda",
                      "waiver",
                      "contract",
                      "consent",
                      "policy",
                      "other"
                    ]
                  },
                  "body": {
                    "type": "string",
                    "minLength": 1
                  },
                  "variables": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    }
                  },
                  "grants": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "consent_text": {
                    "nullable": true,
                    "type": "string"
                  }
                },
                "required": [
                  "code",
                  "name",
                  "kind",
                  "body"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/documents": {
      "get": {
        "operationId": "get-documents",
        "summary": "List documents",
        "description": "Filter with `status` (a state, or `open` for draft and sent) and `q` (title, subject or signer).",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "documents": [
                    {
                      "document_id": "d41c…",
                      "title": "Liability waiver — Dana Reyes",
                      "status": "sent",
                      "template_code": "liability-waiver",
                      "template_version": 2,
                      "subject_name": null,
                      "signers": 2,
                      "signed": 1,
                      "waiting_on": "Sam Manager",
                      "sequential": true,
                      "expires_at": "2026-10-17T00:00:00Z",
                      "sent_at": "2026-10-03T14:22:09Z",
                      "completed_at": null,
                      "void_reason": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "post-documents",
        "summary": "Prepare a document from a template",
        "description": "Renders the published template with the values given and stores the result on the document. Every declared variable needs a value: a contract that ships with a placeholder still in it is worse than one that failed to send.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:write",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Your own key, 8–255 characters. The same key with the same body replays the first response without doing the work again; the same key with a different body is refused rather than absorbed.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "document_id": "d41c…"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "template_code": {
                    "type": "string"
                  },
                  "title": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "values": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "expires_at": {
                    "nullable": true,
                    "type": "string",
                    "format": "date-time"
                  },
                  "sequential": {
                    "type": "boolean"
                  }
                },
                "required": [
                  "template_code"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}": {
      "get": {
        "operationId": "get-documents-by-id",
        "summary": "Show one document",
        "description": "The document, its signers, and the whole event trail with the text hash each event was made against.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "document_id": "d41c…",
                  "title": "Liability waiver — Dana Reyes",
                  "status": "completed",
                  "body": "I, Dana Reyes, …",
                  "body_sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                  "template_code": "liability-waiver",
                  "template_version": 2,
                  "grants": {},
                  "sequential": false,
                  "sent_at": "2026-10-03T14:22:09Z",
                  "completed_at": "2026-10-03T14:22:09Z",
                  "voided_at": null,
                  "void_reason": null,
                  "integrity_ok": true,
                  "signers": [
                    {
                      "signer_id": "5f0a…",
                      "email": "dana@example.com",
                      "full_name": "Dana Reyes",
                      "role": "signer",
                      "sign_order": 1,
                      "status": "signed",
                      "party_id": null,
                      "consented_at": "2026-10-03T14:22:09Z",
                      "signed_at": "2026-10-03T14:22:09Z",
                      "declined_at": null,
                      "decline_reason": null,
                      "token_expires_at": "2026-10-17T00:00:00Z"
                    }
                  ],
                  "events": [
                    {
                      "event_id": "e1…",
                      "kind": "sent",
                      "occurred_at": "2026-10-03T14:22:09Z",
                      "signer_email": null,
                      "ip": null,
                      "user_agent": null,
                      "against_sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                      "detail": null
                    },
                    {
                      "event_id": "e2…",
                      "kind": "consented",
                      "occurred_at": "2026-10-03T14:22:09Z",
                      "signer_email": "dana@example.com",
                      "ip": "203.0.113.9",
                      "user_agent": "Mozilla/5.0 …",
                      "against_sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                      "detail": null
                    },
                    {
                      "event_id": "e3…",
                      "kind": "signed",
                      "occurred_at": "2026-10-03T14:22:09Z",
                      "signer_email": "dana@example.com",
                      "ip": "203.0.113.9",
                      "user_agent": "Mozilla/5.0 …",
                      "signature_method": "typed",
                      "against_sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                      "detail": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/send": {
      "post": {
        "operationId": "post-documents-by-id-send",
        "summary": "Send a document for signature",
        "description": "Returns one signing link per signer, once. The tokens are not stored, only their hashes, so a lost link is replaced by a reminder rather than looked up.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Your own key, 8–255 characters. The same key with the same body replays the first response without doing the work again; the same key with a different body is refused rather than absorbed.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "links": [
                    {
                      "signer_id": "5f0a…",
                      "email": "dana@example.com",
                      "token": "3f9c…64 hex characters"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "signers": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "email": {
                          "type": "string",
                          "format": "email"
                        },
                        "full_name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "role": {
                          "type": "string",
                          "enum": [
                            "signer",
                            "approver",
                            "witness",
                            "cc"
                          ]
                        },
                        "sign_order": {
                          "type": "integer",
                          "minimum": 1,
                          "maximum": 50
                        },
                        "party_id": {
                          "nullable": true,
                          "type": "string",
                          "format": "uuid"
                        }
                      },
                      "required": [
                        "email",
                        "full_name"
                      ],
                      "additionalProperties": false
                    },
                    "minItems": 1,
                    "maxItems": 50
                  }
                },
                "required": [
                  "signers"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/void": {
      "post": {
        "operationId": "post-documents-by-id-void",
        "summary": "Void a document",
        "description": "Needs a reason, which goes on the audit trail. An executed agreement cannot be voided: it is terminated by agreement, not by deletion.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:write",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Your own key, 8–255 characters. The same key with the same body replays the first response without doing the work again; the same key with a different body is refused rather than absorbed.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "voided": true
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500
                  }
                },
                "required": [
                  "reason"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/certificate": {
      "get": {
        "operationId": "get-documents-by-id-certificate",
        "summary": "Fetch the certificate of completion",
        "description": "Issued when the document completes, frozen at issue and hashed. `still_matches_record` re-derives it from the live record and reports any divergence rather than correcting it.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "certificate_id": "c7d0…",
                  "verification_code": "K7QP3MTV9XBD2FHR",
                  "issued_at": "2026-10-03T14:22:09Z",
                  "document_sha256_hex": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                  "certificate_sha256_hex": "592f…",
                  "still_matches_record": true,
                  "payload": {
                    "issuer": {
                      "tenant": "Fern Hollow Stables",
                      "tenant_id": "3a1f…"
                    },
                    "document": {
                      "id": "d41c…",
                      "title": "Liability waiver — Dana Reyes",
                      "sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                      "completed_at": "2026-10-03T14:22:09Z",
                      "template": {
                        "code": "liability-waiver",
                        "version": 2
                      }
                    },
                    "signers": [
                      {
                        "full_name": "Dana Reyes",
                        "email": "dana@example.com",
                        "role": "signer",
                        "sign_order": 1,
                        "status": "signed",
                        "consented_at": "2026-10-03T14:22:09Z",
                        "signed_at": "2026-10-03T14:22:09Z",
                        "signature": {
                          "method": "typed",
                          "value_sha256": "017a…",
                          "signed_against_sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                          "ip": "203.0.113.9"
                        }
                      }
                    ],
                    "events": [
                      {
                        "kind": "signed",
                        "occurred_at": "2026-10-03T14:22:09Z",
                        "signer": "dana@example.com",
                        "ip": "203.0.113.9",
                        "against_sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324"
                      }
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/pdf": {
      "get": {
        "operationId": "get-documents-by-id-pdf",
        "summary": "Download the sealed PDF",
        "description": "The certificate as a PAdES-sealed PDF, with an RFC 3161 timestamp over the signature. Returns base64 bytes and the filename to save them under.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "filename": "certificate-K7QP3MTV9XBD2FHR.pdf",
                  "content_type": "application/pdf",
                  "seal": {
                    "commonName": "SignSealer",
                    "publiclyTrusted": false,
                    "timestamped": true
                  },
                  "bytes_base64": "JVBERi0xLjcK…"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/documents/{id}/bundle": {
      "get": {
        "operationId": "get-documents-by-id-bundle",
        "summary": "Download the evidence bundle",
        "description": "The sealed PDF with the evidence package printed after the audit trail: every message sent about the document, every webhook delivered, and the record's state when the file was made, with the package's SHA-256 on the last page. One PAdES-sealed file. Returns base64 bytes and the filename to save them under.",
        "tags": [
          "Documents"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "filename": "evidence-bundle-K7QP3MTV9XBD2FHR.pdf",
                  "content_type": "application/pdf",
                  "seal": {
                    "commonName": "SignSealer",
                    "publiclyTrusted": false,
                    "timestamped": true
                  },
                  "bytes_base64": "JVBERi0xLjcK…"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/workflows": {
      "get": {
        "operationId": "get-workflows",
        "summary": "List workflows",
        "description": "A workflow is a published template plus the rules for running it: who signs in what order, how long a link lives, and whether it has a public address.",
        "tags": [
          "Workflows"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "workflows": [
                    {
                      "id": "w9b1…",
                      "code": "waiver",
                      "name": "Kayak rental waiver",
                      "kind": "waiver",
                      "template_code": "liability-waiver",
                      "template_published": true,
                      "signer_roles": [
                        {
                          "label": "Participant",
                          "role": "signer",
                          "order": 1,
                          "participant": true
                        }
                      ],
                      "sequential": false,
                      "countersign": false,
                      "expires_days": 7,
                      "remind_after_days": 3,
                      "public_slug": "waiver",
                      "intro": "Read it, answer two questions, sign.",
                      "form_fields": [
                        {
                          "key": "emergency_contact",
                          "label": "Emergency contact",
                          "required": true
                        }
                      ],
                      "active": true,
                      "drafted_by_run": null,
                      "created_at": "2026-10-03T14:22:09Z",
                      "updated_at": "2026-10-03T14:22:09Z",
                      "started": 412,
                      "completed": 398
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/workflows/{id}/start": {
      "post": {
        "operationId": "post-workflows-by-id-start",
        "summary": "Start a workflow for one participant",
        "description": "Prepares the document, sends it to the participant and to every fixed role, and returns the tokens once.",
        "tags": [
          "Workflows"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:workflows",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Your own key, 8–255 characters. The same key with the same body replays the first response without doing the work again; the same key with a different body is refused rather than absorbed.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "document_id": "d41c…",
                  "title": "Kayak rental waiver — Dana Reyes",
                  "expires_at": "2026-10-10T14:22:09Z",
                  "signers": [
                    {
                      "signer_id": "5f0a…",
                      "email": "dana@example.com",
                      "full_name": "Dana Reyes",
                      "role": "signer",
                      "participant": true,
                      "token": "3f9c…"
                    },
                    {
                      "signer_id": "5f0b…",
                      "email": "manager@fernhollow.example",
                      "full_name": "Sam Manager",
                      "role": "signer",
                      "participant": false,
                      "token": "7a21…"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "email": {
                    "type": "string",
                    "format": "email"
                  },
                  "full_name": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "phone": {
                    "type": "string",
                    "maxLength": 40
                  },
                  "fields": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "values": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  },
                  "external_ref": {
                    "type": "string",
                    "maxLength": 200
                  }
                },
                "required": [
                  "email",
                  "full_name"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/subjects": {
      "put": {
        "operationId": "put-subjects",
        "summary": "Import a reservation or activity, and build its packet",
        "description": "Keyed on (provider, external_id), so importing the same reservation twice is one reservation, which is why this needs no idempotency key. Participants and the packet are built in the same call, because a caller who imported a reservation always wants to know what is now required.",
        "tags": [
          "Subjects"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:subjects",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "subject_id": "s2e4…",
                  "packet": {
                    "packet_id": "p6c9…",
                    "code": "RES-88213",
                    "added": 2,
                    "dropped": 0,
                    "state": "open",
                    "required": 2,
                    "completed": 0,
                    "outstanding": 2,
                    "not_started": 2
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "kind": {
                    "type": "string",
                    "enum": [
                      "reservation",
                      "activity"
                    ]
                  },
                  "provider": {
                    "type": "string",
                    "pattern": "^[a-z][a-z0-9_-]*$"
                  },
                  "external_id": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 200
                  },
                  "label": {
                    "type": "string",
                    "maxLength": 200
                  },
                  "starts_on": {
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  "ends_on": {
                    "nullable": true,
                    "type": "string",
                    "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                  },
                  "facts": {
                    "type": "object",
                    "additionalProperties": true
                  },
                  "participants": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "ref": {
                          "type": "string",
                          "maxLength": 64
                        },
                        "full_name": {
                          "type": "string",
                          "minLength": 1,
                          "maxLength": 200
                        },
                        "email": {
                          "type": "string",
                          "format": "email"
                        },
                        "phone": {
                          "type": "string",
                          "maxLength": 40
                        },
                        "date_of_birth": {
                          "type": "string",
                          "pattern": "^\\d{4}-\\d{2}-\\d{2}$"
                        },
                        "is_primary": {
                          "type": "boolean"
                        },
                        "guardian_ref": {
                          "type": "string",
                          "maxLength": 64
                        }
                      },
                      "required": [
                        "full_name"
                      ],
                      "additionalProperties": false
                    },
                    "maxItems": 60
                  }
                },
                "required": [
                  "external_id",
                  "starts_on"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/packets/{id}": {
      "get": {
        "operationId": "get-packets-by-id",
        "summary": "Show a packet",
        "description": "Who owes what, where each one has got to, and a readiness state a door lock can wait on.",
        "tags": [
          "Packets"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:read",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "packet_id": "p6c9…",
                  "code": "RES-88213",
                  "status": "open",
                  "ready_at": null,
                  "subject": {
                    "id": "s2e4…",
                    "kind": "reservation",
                    "label": "Reyes party, 4 Oct",
                    "provider": "deckpos",
                    "external_id": "RES-88213",
                    "starts_on": "2026-10-04",
                    "ends_on": "2026-10-04",
                    "facts": {}
                  },
                  "readiness": {
                    "required": 2,
                    "completed": 1,
                    "outstanding": 1,
                    "blocked": 0
                  },
                  "items": [
                    {
                      "item_id": "i1…",
                      "requirement": "waiver",
                      "workflow": "waiver",
                      "required": true,
                      "participant": {
                        "id": "pa1…",
                        "full_name": "Dana Reyes",
                        "email": "dana@example.com",
                        "is_minor": false,
                        "signs_for_them": null
                      },
                      "document_id": "d41c…",
                      "status": "completed"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/packets/items/{id}/start": {
      "post": {
        "operationId": "post-packets-items-by-id-start",
        "summary": "Start one packet item",
        "description": "Renders the item's workflow for the person who owes it. A minor's document is started for their guardian, because the guardian is who signs.",
        "tags": [
          "Packets"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:subjects",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Your own key, 8–255 characters. The same key with the same body replays the first response without doing the work again; the same key with a different body is refused rather than absorbed.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "document_id": "d41d…",
                  "title": "Kayak rental waiver — Dana Reyes",
                  "expires_at": "2026-10-10T14:22:09Z",
                  "signers": [
                    {
                      "signer_id": "5f0c…",
                      "email": "dana@example.com",
                      "full_name": "Dana Reyes",
                      "role": "signer",
                      "participant": true,
                      "token": "3f9c…"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks": {
      "get": {
        "operationId": "get-webhooks",
        "summary": "List webhook endpoints",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:webhooks",
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "endpoints": [
                    {
                      "id": "h4a7…",
                      "url": "https://pms.example.com/hooks/signsealer",
                      "label": "Booking system",
                      "events": [
                        "signing.completed",
                        "signing.declined"
                      ],
                      "active": true,
                      "failures": 0,
                      "paused_at": null,
                      "last_delivered_at": "2026-10-03T14:22:09Z",
                      "created_at": "2026-10-03T14:22:09Z",
                      "queued": 0,
                      "dead": 0
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "post-webhooks",
        "summary": "Add a webhook endpoint",
        "description": "Returns the signing secret once and never again. It is sealed at rest; a caller who loses it replaces the endpoint.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:webhooks",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "description": "Your own key, 8–255 characters. The same key with the same body replays the first response without doing the work again; the same key with a different body is refused rather than absorbed.",
            "schema": {
              "type": "string",
              "minLength": 8,
              "maxLength": 255
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "id": "h4a7…",
                  "secret": "whsec_…48 hex characters, shown once"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri",
                    "pattern": "^https://"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "maxItems": 30
                  },
                  "label": {
                    "type": "string",
                    "maxLength": 80
                  }
                },
                "required": [
                  "url"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}": {
      "patch": {
        "operationId": "patch-webhooks-by-id",
        "summary": "Change a webhook endpoint",
        "description": "Turning an endpoint back on forgives its failure count.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:webhooks",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "updated": true
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "active": {
                    "type": "boolean"
                  },
                  "events": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "minItems": 1,
                    "maxItems": 30
                  },
                  "label": {
                    "type": "string",
                    "maxLength": 80
                  }
                },
                "additionalProperties": false
              }
            }
          }
        }
      },
      "delete": {
        "operationId": "delete-webhooks-by-id",
        "summary": "Remove a webhook endpoint",
        "description": "Needs `?reason=`, which goes on the audit trail.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:webhooks",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "deleted": true
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}/rotate": {
      "post": {
        "operationId": "post-webhooks-by-id-rotate",
        "summary": "Rotate a webhook endpoint's secret",
        "description": "A new secret, returned once. For 24 hours every delivery is signed with both — the signature header carries two comma-separated `v1=` values, the new secret's first — so a receiver can switch without dropping a delivery. After that the old secret is forgotten.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:webhooks",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "secret": "whsec_…shown once",
                  "previous_valid_for_seconds": 86400
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/{id}/deliveries": {
      "get": {
        "operationId": "get-webhooks-by-id-deliveries",
        "summary": "List an endpoint's recent deliveries",
        "description": "The last fifty, newest first: event, status, attempts, the next attempt, the last error and the document. A replay names the delivery it repeats in `replay_of`.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:webhooks",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "deliveries": [
                    {
                      "id": "dl1…",
                      "endpoint_id": "h4a7…",
                      "event": "signing.completed",
                      "status": "delivered",
                      "attempts": 1,
                      "next_attempt_at": "2026-10-03T14:22:09Z",
                      "last_error": null,
                      "response_status": 200,
                      "created_at": "2026-10-03T14:22:09Z",
                      "delivered_at": "2026-10-03T14:22:09Z",
                      "replay_of": null,
                      "document_id": "d41c…",
                      "document_title": "Liability waiver — Dana Reyes"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/webhooks/deliveries/{id}/replay": {
      "post": {
        "operationId": "post-webhooks-deliveries-by-id-replay",
        "summary": "Send a delivery again",
        "description": "Queues a delivered, failed or dead delivery again as a new delivery with the same event and body, marked as a replay of the original. One still in the queue is refused; so is a second replay while the first is queued. A replay waits like any other if the endpoint is off or paused.",
        "tags": [
          "Webhooks"
        ],
        "security": [
          {
            "apiKey": []
          }
        ],
        "x-scope": "signing:webhooks",
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "delivery_id": "dl2…"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    },
    "/v1/sign/{token}": {
      "get": {
        "operationId": "get-sign-by-token",
        "summary": "Read a document from a signing link",
        "description": "Everything the signing page needs from one token: the text and its hash, who is being asked, who else is on it, whether it is this signer's turn, and — when it will not take a signature — why, in a sentence a person can read. Returns a body even for a token that matches nothing, so a bad link and an expired one fail identically.",
        "tags": [
          "Signing"
        ],
        "security": [],
        "x-scope": "none",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "ok": true,
                  "reason": null,
                  "document_id": "d41c…",
                  "title": "Liability waiver — Dana Reyes",
                  "body": "I, Dana Reyes, …",
                  "body_sha256_hex": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                  "document_status": "sent",
                  "sequential": false,
                  "expires_at": "2026-10-17T00:00:00Z",
                  "tenant_name": "Fern Hollow Stables",
                  "signer_id": "5f0a…",
                  "full_name": "Dana Reyes",
                  "email": "dana@example.com",
                  "signer_role": "signer",
                  "sign_order": 1,
                  "signer_status": "pending",
                  "consented_at": null,
                  "signed_at": null,
                  "template_kind": "waiver",
                  "grants": {},
                  "is_my_turn": true,
                  "waiting_on": null,
                  "signers": [
                    {
                      "full_name": "Dana Reyes",
                      "role": "signer",
                      "sign_order": 1,
                      "status": "pending",
                      "signed_at": null,
                      "is_me": true
                    }
                  ],
                  "fields": [
                    {
                      "key": "initials",
                      "label": "Initial here",
                      "kind": "initials",
                      "required": true,
                      "about": null,
                      "supplied": false
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "post-sign-by-token",
        "summary": "Sign",
        "description": "Typed or drawn, both equally valid: what matters is intent. `captured` is for a signature taken where there was no network — the server records when it received it and keeps the device's claim beside it, with the clock skew computed rather than accepted.",
        "tags": [
          "Signing"
        ],
        "security": [],
        "x-scope": "none",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "event_id": "e3…"
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "method": {
                    "type": "string",
                    "enum": [
                      "typed",
                      "drawn",
                      "clicked",
                      "uploaded"
                    ]
                  },
                  "value": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 400000
                  },
                  "captured": {
                    "type": "object",
                    "properties": {
                      "offline": {
                        "type": "boolean"
                      },
                      "at": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "device": {
                        "type": "string",
                        "maxLength": 80
                      }
                    },
                    "additionalProperties": false
                  }
                },
                "required": [
                  "method",
                  "value"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/sign/{token}/consent": {
      "post": {
        "operationId": "post-sign-by-token-consent",
        "summary": "Record consent to sign electronically",
        "description": "Must happen before the signature, and is its own event for that reason: ESIGN requires consent to precede the transaction, and a system that recorded both in the same instant could not show that it did.",
        "tags": [
          "Signing"
        ],
        "security": [],
        "x-scope": "none",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "consented": true
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "captured": {
                    "type": "object",
                    "properties": {
                      "offline": {
                        "type": "boolean"
                      },
                      "at": {
                        "type": "string",
                        "format": "date-time"
                      },
                      "device": {
                        "type": "string",
                        "maxLength": 80
                      }
                    },
                    "additionalProperties": false
                  }
                },
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/sign/{token}/fields": {
      "post": {
        "operationId": "post-sign-by-token-fields",
        "summary": "Supply a required field",
        "description": "Initials, a checkbox, a date. A signature is refused while anything required is unsupplied, and that refusal is in the database rather than in the form — so a second interface cannot go around it.",
        "tags": [
          "Signing"
        ],
        "security": [],
        "x-scope": "none",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "supplied": true
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "key": {
                    "type": "string",
                    "pattern": "^[a-z][a-z0-9_]{0,58}$"
                  },
                  "value": {
                    "type": "string",
                    "maxLength": 20000
                  },
                  "about": {
                    "nullable": true,
                    "type": "string",
                    "maxLength": 200
                  }
                },
                "required": [
                  "key",
                  "value"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/sign/{token}/decline": {
      "post": {
        "operationId": "post-sign-by-token-decline",
        "summary": "Decline to sign",
        "description": "With a reason. A decline is a person saying no, which is not the same as still waiting — a packet containing one is blocked rather than outstanding, so nobody chases somebody who already answered.",
        "tags": [
          "Signing"
        ],
        "security": [],
        "x-scope": "none",
        "parameters": [
          {
            "name": "token",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "declined": true
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        },
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "reason": {
                    "type": "string",
                    "minLength": 1,
                    "maxLength": 500
                  }
                },
                "required": [
                  "reason"
                ],
                "additionalProperties": false
              }
            }
          }
        }
      }
    },
    "/v1/verify/{code}": {
      "get": {
        "operationId": "get-verify-by-code",
        "summary": "Check a certificate by its printed code",
        "description": "Anonymous, because the point is that a stranger holding a printed page can check it. Answers three separate questions: whether the certificate exists, whether a document you hold matches it, and whether it still matches the record behind it. The third is a finding, never a correction.",
        "tags": [
          "Verify"
        ],
        "security": [],
        "x-scope": "none",
        "parameters": [
          {
            "name": "code",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Done.",
            "content": {
              "application/json": {
                "example": {
                  "found": true,
                  "verification_code": "K7QP3MTV9XBD2FHR",
                  "issued_at": "2026-10-03T14:22:09Z",
                  "issuer": "Fern Hollow Stables",
                  "title": "Liability waiver — Dana Reyes",
                  "document_sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324",
                  "document_matches": true,
                  "still_matches_record": true,
                  "divergence": null,
                  "completed_at": "2026-10-03T14:22:09Z",
                  "redacted_at": null,
                  "signers": [
                    {
                      "full_name": "Dana Reyes",
                      "email": "dana@example.com",
                      "role": "signer",
                      "sign_order": 1,
                      "status": "signed",
                      "consented_at": "2026-10-03T14:22:09Z",
                      "signed_at": "2026-10-03T14:22:09Z"
                    }
                  ],
                  "events": [
                    {
                      "kind": "signed",
                      "occurred_at": "2026-10-03T14:22:09Z",
                      "signer": "dana@example.com",
                      "against_sha256": "e362cc76dae17bbe2a9fc551d9b795fa4e0f77fb488eb748378a125b11f36324"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "description": "The request could not be read.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "bad_request",
                    "message": "The request could not be read."
                  }
                }
              }
            }
          },
          "401": {
            "description": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "unauthorized",
                    "message": "No key, or a key that is not live. Unknown, revoked and expired all answer the same way."
                  }
                }
              }
            }
          },
          "403": {
            "description": "The key is live but its scopes do not carry this.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "forbidden",
                    "message": "The key is live but its scopes do not carry this."
                  }
                }
              }
            }
          },
          "404": {
            "description": "No such thing, in this account.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "not_found",
                    "message": "No such thing, in this account."
                  }
                }
              }
            }
          },
          "409": {
            "description": "The same idempotency key was used for a different request, or the work is still running.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "conflict",
                    "message": "The same idempotency key was used for a different request, or the work is still running."
                  }
                }
              }
            }
          },
          "413": {
            "description": "The body is larger than a signing request ever is.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "too_large",
                    "message": "The body is larger than a signing request ever is."
                  }
                }
              }
            }
          },
          "422": {
            "description": "The body did not validate, or the engine refused it. The message is the reason.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "invalid",
                    "message": "The body did not validate, or the engine refused it. The message is the reason."
                  }
                }
              }
            }
          },
          "429": {
            "description": "Too many attempts. The message says the budget.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "rate_limited",
                    "message": "Too many attempts. The message says the budget."
                  }
                }
              }
            }
          },
          "500": {
            "description": "Something went wrong on our side. Quote the x-request-id.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "example": {
                  "error": {
                    "code": "internal",
                    "message": "Something went wrong on our side. Quote the x-request-id."
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
